From 7a716b4c9c587182dfa752a6a8f3cd8e12eff6fa Mon Sep 17 00:00:00 2001 From: Dmitriy Petrov Date: Tue, 13 Oct 2026 06:53:52 +0300 Subject: [PATCH] Improve VPN status reporting and recovery --- .agents/skills/lemana-vpn-operations/SKILL.md | 4 +- .agents/skills/lemana-vpn-testing/SKILL.md | 6 +- AGENTS.md | 4 +- README.md | 797 ++++++--------- app/Sources/LemanaVPN/BoundedLog.swift | 38 + app/Sources/LemanaVPN/LemanaVPNApp.swift | 482 +++++++--- app/Sources/LemanaVPN/SessionTiming.swift | 71 ++ app/Sources/LemanaVPN/VPNIcons.swift | 215 +++++ app/Sources/LemanaVPN/VPNManager.swift | 860 +++++++++++------ artifacts/icon-family-v1/README.md | 19 + artifacts/icon-family-v1/draw_icons.py | 168 ++++ artifacts/icon-family-v1/icon-sheet-dark.png | Bin 0 -> 268079 bytes artifacts/icon-family-v1/icon-sheet-dark.svg | 1 + artifacts/icon-family-v1/icon-sheet-light.png | Bin 0 -> 267643 bytes artifacts/icon-family-v1/icon-sheet-light.svg | 1 + .../icon-family-v1/lemana-vpn-icons-v1.zip | Bin 0 -> 29676 bytes artifacts/icon-family-v1/manifest.json | 308 ++++++ .../icon-family-v1/png/action-cancel-dark.png | Bin 0 -> 923 bytes .../png/action-cancel-light.png | Bin 0 -> 995 bytes .../png/action-connect-dark.png | Bin 0 -> 1535 bytes .../png/action-connect-light.png | Bin 0 -> 1570 bytes .../icon-family-v1/png/action-copy-dark.png | Bin 0 -> 692 bytes .../icon-family-v1/png/action-copy-light.png | Bin 0 -> 703 bytes .../png/action-disconnect-dark.png | Bin 0 -> 1808 bytes .../png/action-disconnect-light.png | Bin 0 -> 1846 bytes .../icon-family-v1/png/action-import-dark.png | Bin 0 -> 969 bytes .../png/action-import-light.png | Bin 0 -> 966 bytes .../icon-family-v1/png/action-logs-dark.png | Bin 0 -> 875 bytes .../icon-family-v1/png/action-logs-light.png | Bin 0 -> 903 bytes .../png/action-password-dark.png | Bin 0 -> 1919 bytes .../png/action-password-light.png | Bin 0 -> 2059 bytes .../icon-family-v1/png/action-quit-dark.png | Bin 0 -> 970 bytes .../icon-family-v1/png/action-quit-light.png | Bin 0 -> 976 bytes .../png/action-refresh-dark.png | Bin 0 -> 2465 bytes .../png/action-refresh-light.png | Bin 0 -> 2501 bytes .../icon-family-v1/png/format-clock-dark.png | Bin 0 -> 3152 bytes .../icon-family-v1/png/format-clock-light.png | Bin 0 -> 3220 bytes .../icon-family-v1/png/format-ring-dark.png | Bin 0 -> 3935 bytes .../icon-family-v1/png/format-ring-light.png | Bin 0 -> 4087 bytes .../icon-family-v1/png/format-shield-dark.png | Bin 0 -> 3549 bytes .../png/format-shield-light.png | Bin 0 -> 3665 bytes .../icon-family-v1/png/format-time-dark.png | Bin 0 -> 6717 bytes .../icon-family-v1/png/format-time-light.png | Bin 0 -> 6744 bytes .../icon-family-v1/png/source-auto-dark.png | Bin 0 -> 1839 bytes .../icon-family-v1/png/source-auto-light.png | Bin 0 -> 1873 bytes .../icon-family-v1/png/source-local-dark.png | Bin 0 -> 1185 bytes .../icon-family-v1/png/source-local-light.png | Bin 0 -> 1224 bytes .../icon-family-v1/png/source-manual-dark.png | Bin 0 -> 1212 bytes .../png/source-manual-light.png | Bin 0 -> 1245 bytes .../icon-family-v1/png/source-vault-dark.png | Bin 0 -> 2586 bytes .../icon-family-v1/png/source-vault-light.png | Bin 0 -> 2599 bytes .../icon-family-v1/png/time-expired-dark.png | Bin 0 -> 4095 bytes .../icon-family-v1/png/time-expired-light.png | Bin 0 -> 4086 bytes .../icon-family-v1/png/time-half-dark.png | Bin 0 -> 3653 bytes .../icon-family-v1/png/time-half-light.png | Bin 0 -> 3790 bytes .../icon-family-v1/png/time-hour-dark.png | Bin 0 -> 3348 bytes .../icon-family-v1/png/time-hour-light.png | Bin 0 -> 3378 bytes .../icon-family-v1/png/time-quarter-dark.png | Bin 0 -> 3881 bytes .../png/time-quarter-hour-dark.png | Bin 0 -> 3232 bytes .../png/time-quarter-hour-light.png | Bin 0 -> 3292 bytes .../icon-family-v1/png/time-quarter-light.png | Bin 0 -> 3954 bytes .../icon-family-v1/png/time-start-dark.png | Bin 0 -> 3746 bytes .../icon-family-v1/png/time-start-light.png | Bin 0 -> 3868 bytes .../png/time-three-quarter-dark.png | Bin 0 -> 3338 bytes .../png/time-three-quarter-light.png | Bin 0 -> 3398 bytes .../icon-family-v1/png/time-unknown-dark.png | Bin 0 -> 2865 bytes .../icon-family-v1/png/time-unknown-light.png | Bin 0 -> 2930 bytes .../icon-family-v1/png/vpn-connected-dark.png | Bin 0 -> 3320 bytes .../png/vpn-connected-light.png | Bin 0 -> 3366 bytes .../png/vpn-connecting-dark.png | Bin 0 -> 2852 bytes .../png/vpn-connecting-light.png | Bin 0 -> 2922 bytes .../icon-family-v1/png/vpn-error-dark.png | Bin 0 -> 3243 bytes .../icon-family-v1/png/vpn-error-light.png | Bin 0 -> 3307 bytes .../icon-family-v1/png/vpn-network-dark.png | Bin 0 -> 3565 bytes .../icon-family-v1/png/vpn-network-light.png | Bin 0 -> 3647 bytes artifacts/icon-family-v1/png/vpn-off-dark.png | Bin 0 -> 3005 bytes .../icon-family-v1/png/vpn-off-light.png | Bin 0 -> 3080 bytes .../icon-family-v1/png/vpn-reconnect-dark.png | Bin 0 -> 3903 bytes .../png/vpn-reconnect-light.png | Bin 0 -> 3971 bytes .../icon-family-v1/png/vpn-setup-dark.png | Bin 0 -> 3018 bytes .../icon-family-v1/png/vpn-setup-light.png | Bin 0 -> 3073 bytes .../icon-family-v1/png/vpn-unknown-dark.png | Bin 0 -> 3565 bytes .../icon-family-v1/png/vpn-unknown-light.png | Bin 0 -> 3654 bytes .../icon-family-v1/png/vpn-unlock-dark.png | Bin 0 -> 3519 bytes .../icon-family-v1/png/vpn-unlock-light.png | Bin 0 -> 3568 bytes .../icon-family-v1/svg/action-cancel-dark.svg | 1 + .../svg/action-cancel-light.svg | 1 + .../svg/action-connect-dark.svg | 1 + .../svg/action-connect-light.svg | 1 + .../icon-family-v1/svg/action-copy-dark.svg | 1 + .../icon-family-v1/svg/action-copy-light.svg | 1 + .../svg/action-disconnect-dark.svg | 1 + .../svg/action-disconnect-light.svg | 1 + .../icon-family-v1/svg/action-import-dark.svg | 1 + .../svg/action-import-light.svg | 1 + .../icon-family-v1/svg/action-logs-dark.svg | 1 + .../icon-family-v1/svg/action-logs-light.svg | 1 + .../svg/action-password-dark.svg | 1 + .../svg/action-password-light.svg | 1 + .../icon-family-v1/svg/action-quit-dark.svg | 1 + .../icon-family-v1/svg/action-quit-light.svg | 1 + .../svg/action-refresh-dark.svg | 1 + .../svg/action-refresh-light.svg | 1 + .../icon-family-v1/svg/format-clock-dark.svg | 1 + .../icon-family-v1/svg/format-clock-light.svg | 1 + .../icon-family-v1/svg/format-ring-dark.svg | 1 + .../icon-family-v1/svg/format-ring-light.svg | 1 + .../icon-family-v1/svg/format-shield-dark.svg | 1 + .../svg/format-shield-light.svg | 1 + .../icon-family-v1/svg/format-time-dark.svg | 1 + .../icon-family-v1/svg/format-time-light.svg | 1 + .../icon-family-v1/svg/source-auto-dark.svg | 1 + .../icon-family-v1/svg/source-auto-light.svg | 1 + .../icon-family-v1/svg/source-local-dark.svg | 1 + .../icon-family-v1/svg/source-local-light.svg | 1 + .../icon-family-v1/svg/source-manual-dark.svg | 1 + .../svg/source-manual-light.svg | 1 + .../icon-family-v1/svg/source-vault-dark.svg | 1 + .../icon-family-v1/svg/source-vault-light.svg | 1 + .../icon-family-v1/svg/time-expired-dark.svg | 1 + .../icon-family-v1/svg/time-expired-light.svg | 1 + .../icon-family-v1/svg/time-half-dark.svg | 1 + .../icon-family-v1/svg/time-half-light.svg | 1 + .../icon-family-v1/svg/time-hour-dark.svg | 1 + .../icon-family-v1/svg/time-hour-light.svg | 1 + .../icon-family-v1/svg/time-quarter-dark.svg | 1 + .../svg/time-quarter-hour-dark.svg | 1 + .../svg/time-quarter-hour-light.svg | 1 + .../icon-family-v1/svg/time-quarter-light.svg | 1 + .../icon-family-v1/svg/time-start-dark.svg | 1 + .../icon-family-v1/svg/time-start-light.svg | 1 + .../svg/time-three-quarter-dark.svg | 1 + .../svg/time-three-quarter-light.svg | 1 + .../icon-family-v1/svg/time-unknown-dark.svg | 1 + .../icon-family-v1/svg/time-unknown-light.svg | 1 + .../icon-family-v1/svg/vpn-connected-dark.svg | 1 + .../svg/vpn-connected-light.svg | 1 + .../svg/vpn-connecting-dark.svg | 1 + .../svg/vpn-connecting-light.svg | 1 + .../icon-family-v1/svg/vpn-error-dark.svg | 1 + .../icon-family-v1/svg/vpn-error-light.svg | 1 + .../icon-family-v1/svg/vpn-network-dark.svg | 1 + .../icon-family-v1/svg/vpn-network-light.svg | 1 + artifacts/icon-family-v1/svg/vpn-off-dark.svg | 1 + .../icon-family-v1/svg/vpn-off-light.svg | 1 + .../icon-family-v1/svg/vpn-reconnect-dark.svg | 1 + .../svg/vpn-reconnect-light.svg | 1 + .../icon-family-v1/svg/vpn-setup-dark.svg | 1 + .../icon-family-v1/svg/vpn-setup-light.svg | 1 + .../icon-family-v1/svg/vpn-unknown-dark.svg | 1 + .../icon-family-v1/svg/vpn-unknown-light.svg | 1 + .../icon-family-v1/svg/vpn-unlock-dark.svg | 1 + .../icon-family-v1/svg/vpn-unlock-light.svg | 1 + bin/lemana-vpn-import-yandex.py | 239 +++++ bin/vpn-lemanapro.sh | 907 +++++++++++++----- docs/goals/compact-menu/GOAL.md | 3 + docs/goals/compact-menu/PLAN.md | 41 + docs/goals/configured-auth-ui/GOAL.md | 3 + docs/goals/configured-auth-ui/PLAN.md | 44 + docs/goals/logging-and-config/GOAL.md | 3 + docs/goals/logging-and-config/PLAN.md | 51 + docs/goals/manual-first-auth-flow/GOAL.md | 14 +- docs/goals/manual-first-auth-flow/PLAN.md | 442 +-------- docs/goals/startup-dns-and-icons/GOAL.md | 19 + docs/goals/startup-dns-and-icons/PLAN.md | 40 + docs/goals/two-auth-modes/GOAL.md | 13 + docs/goals/two-auth-modes/PLAN.md | 201 ++++ docs/goals/yandex-key-import/GOAL.md | 3 + docs/goals/yandex-key-import/PLAN.md | 45 + install.sh | 521 ++++++---- libexec/lemana-vpn-dns-cleanup | 398 +++++++- templates/bitwarden-auto.env | 10 + templates/keychain-auto.env | 10 + templates/manual-keychain.env | 10 + templates/openconnect-lite-config.toml | 3 +- tests/auth_retry.py | 123 +++ tests/auth_settings.py | 98 ++ tests/configuration.py | 181 ++++ tests/connection_runtime.py | 137 +++ tests/dns_cli.py | 169 ++++ tests/dns_recovery.py | 362 +++++++ tests/icons.py | 95 ++ tests/logging.py | 176 ++++ tests/menu.py | 512 ++++++++++ tests/session_stop.py | 207 ++++ tests/smoke.sh | 447 +++++++-- tests/yandex_import.py | 294 ++++++ uninstall.sh | 1 + 188 files changed, 6953 insertions(+), 1911 deletions(-) create mode 100644 app/Sources/LemanaVPN/BoundedLog.swift create mode 100644 app/Sources/LemanaVPN/SessionTiming.swift create mode 100644 app/Sources/LemanaVPN/VPNIcons.swift create mode 100644 artifacts/icon-family-v1/README.md create mode 100644 artifacts/icon-family-v1/draw_icons.py create mode 100644 artifacts/icon-family-v1/icon-sheet-dark.png create mode 100644 artifacts/icon-family-v1/icon-sheet-dark.svg create mode 100644 artifacts/icon-family-v1/icon-sheet-light.png create mode 100644 artifacts/icon-family-v1/icon-sheet-light.svg create mode 100644 artifacts/icon-family-v1/lemana-vpn-icons-v1.zip create mode 100644 artifacts/icon-family-v1/manifest.json create mode 100644 artifacts/icon-family-v1/png/action-cancel-dark.png create mode 100644 artifacts/icon-family-v1/png/action-cancel-light.png create mode 100644 artifacts/icon-family-v1/png/action-connect-dark.png create mode 100644 artifacts/icon-family-v1/png/action-connect-light.png create mode 100644 artifacts/icon-family-v1/png/action-copy-dark.png create mode 100644 artifacts/icon-family-v1/png/action-copy-light.png create mode 100644 artifacts/icon-family-v1/png/action-disconnect-dark.png create mode 100644 artifacts/icon-family-v1/png/action-disconnect-light.png create mode 100644 artifacts/icon-family-v1/png/action-import-dark.png create mode 100644 artifacts/icon-family-v1/png/action-import-light.png create mode 100644 artifacts/icon-family-v1/png/action-logs-dark.png create mode 100644 artifacts/icon-family-v1/png/action-logs-light.png create mode 100644 artifacts/icon-family-v1/png/action-password-dark.png create mode 100644 artifacts/icon-family-v1/png/action-password-light.png create mode 100644 artifacts/icon-family-v1/png/action-quit-dark.png create mode 100644 artifacts/icon-family-v1/png/action-quit-light.png create mode 100644 artifacts/icon-family-v1/png/action-refresh-dark.png create mode 100644 artifacts/icon-family-v1/png/action-refresh-light.png create mode 100644 artifacts/icon-family-v1/png/format-clock-dark.png create mode 100644 artifacts/icon-family-v1/png/format-clock-light.png create mode 100644 artifacts/icon-family-v1/png/format-ring-dark.png create mode 100644 artifacts/icon-family-v1/png/format-ring-light.png create mode 100644 artifacts/icon-family-v1/png/format-shield-dark.png create mode 100644 artifacts/icon-family-v1/png/format-shield-light.png create mode 100644 artifacts/icon-family-v1/png/format-time-dark.png create mode 100644 artifacts/icon-family-v1/png/format-time-light.png create mode 100644 artifacts/icon-family-v1/png/source-auto-dark.png create mode 100644 artifacts/icon-family-v1/png/source-auto-light.png create mode 100644 artifacts/icon-family-v1/png/source-local-dark.png create mode 100644 artifacts/icon-family-v1/png/source-local-light.png create mode 100644 artifacts/icon-family-v1/png/source-manual-dark.png create mode 100644 artifacts/icon-family-v1/png/source-manual-light.png create mode 100644 artifacts/icon-family-v1/png/source-vault-dark.png create mode 100644 artifacts/icon-family-v1/png/source-vault-light.png create mode 100644 artifacts/icon-family-v1/png/time-expired-dark.png create mode 100644 artifacts/icon-family-v1/png/time-expired-light.png create mode 100644 artifacts/icon-family-v1/png/time-half-dark.png create mode 100644 artifacts/icon-family-v1/png/time-half-light.png create mode 100644 artifacts/icon-family-v1/png/time-hour-dark.png create mode 100644 artifacts/icon-family-v1/png/time-hour-light.png create mode 100644 artifacts/icon-family-v1/png/time-quarter-dark.png create mode 100644 artifacts/icon-family-v1/png/time-quarter-hour-dark.png create mode 100644 artifacts/icon-family-v1/png/time-quarter-hour-light.png create mode 100644 artifacts/icon-family-v1/png/time-quarter-light.png create mode 100644 artifacts/icon-family-v1/png/time-start-dark.png create mode 100644 artifacts/icon-family-v1/png/time-start-light.png create mode 100644 artifacts/icon-family-v1/png/time-three-quarter-dark.png create mode 100644 artifacts/icon-family-v1/png/time-three-quarter-light.png create mode 100644 artifacts/icon-family-v1/png/time-unknown-dark.png create mode 100644 artifacts/icon-family-v1/png/time-unknown-light.png create mode 100644 artifacts/icon-family-v1/png/vpn-connected-dark.png create mode 100644 artifacts/icon-family-v1/png/vpn-connected-light.png create mode 100644 artifacts/icon-family-v1/png/vpn-connecting-dark.png create mode 100644 artifacts/icon-family-v1/png/vpn-connecting-light.png create mode 100644 artifacts/icon-family-v1/png/vpn-error-dark.png create mode 100644 artifacts/icon-family-v1/png/vpn-error-light.png create mode 100644 artifacts/icon-family-v1/png/vpn-network-dark.png create mode 100644 artifacts/icon-family-v1/png/vpn-network-light.png create mode 100644 artifacts/icon-family-v1/png/vpn-off-dark.png create mode 100644 artifacts/icon-family-v1/png/vpn-off-light.png create mode 100644 artifacts/icon-family-v1/png/vpn-reconnect-dark.png create mode 100644 artifacts/icon-family-v1/png/vpn-reconnect-light.png create mode 100644 artifacts/icon-family-v1/png/vpn-setup-dark.png create mode 100644 artifacts/icon-family-v1/png/vpn-setup-light.png create mode 100644 artifacts/icon-family-v1/png/vpn-unknown-dark.png create mode 100644 artifacts/icon-family-v1/png/vpn-unknown-light.png create mode 100644 artifacts/icon-family-v1/png/vpn-unlock-dark.png create mode 100644 artifacts/icon-family-v1/png/vpn-unlock-light.png create mode 100644 artifacts/icon-family-v1/svg/action-cancel-dark.svg create mode 100644 artifacts/icon-family-v1/svg/action-cancel-light.svg create mode 100644 artifacts/icon-family-v1/svg/action-connect-dark.svg create mode 100644 artifacts/icon-family-v1/svg/action-connect-light.svg create mode 100644 artifacts/icon-family-v1/svg/action-copy-dark.svg create mode 100644 artifacts/icon-family-v1/svg/action-copy-light.svg create mode 100644 artifacts/icon-family-v1/svg/action-disconnect-dark.svg create mode 100644 artifacts/icon-family-v1/svg/action-disconnect-light.svg create mode 100644 artifacts/icon-family-v1/svg/action-import-dark.svg create mode 100644 artifacts/icon-family-v1/svg/action-import-light.svg create mode 100644 artifacts/icon-family-v1/svg/action-logs-dark.svg create mode 100644 artifacts/icon-family-v1/svg/action-logs-light.svg create mode 100644 artifacts/icon-family-v1/svg/action-password-dark.svg create mode 100644 artifacts/icon-family-v1/svg/action-password-light.svg create mode 100644 artifacts/icon-family-v1/svg/action-quit-dark.svg create mode 100644 artifacts/icon-family-v1/svg/action-quit-light.svg create mode 100644 artifacts/icon-family-v1/svg/action-refresh-dark.svg create mode 100644 artifacts/icon-family-v1/svg/action-refresh-light.svg create mode 100644 artifacts/icon-family-v1/svg/format-clock-dark.svg create mode 100644 artifacts/icon-family-v1/svg/format-clock-light.svg create mode 100644 artifacts/icon-family-v1/svg/format-ring-dark.svg create mode 100644 artifacts/icon-family-v1/svg/format-ring-light.svg create mode 100644 artifacts/icon-family-v1/svg/format-shield-dark.svg create mode 100644 artifacts/icon-family-v1/svg/format-shield-light.svg create mode 100644 artifacts/icon-family-v1/svg/format-time-dark.svg create mode 100644 artifacts/icon-family-v1/svg/format-time-light.svg create mode 100644 artifacts/icon-family-v1/svg/source-auto-dark.svg create mode 100644 artifacts/icon-family-v1/svg/source-auto-light.svg create mode 100644 artifacts/icon-family-v1/svg/source-local-dark.svg create mode 100644 artifacts/icon-family-v1/svg/source-local-light.svg create mode 100644 artifacts/icon-family-v1/svg/source-manual-dark.svg create mode 100644 artifacts/icon-family-v1/svg/source-manual-light.svg create mode 100644 artifacts/icon-family-v1/svg/source-vault-dark.svg create mode 100644 artifacts/icon-family-v1/svg/source-vault-light.svg create mode 100644 artifacts/icon-family-v1/svg/time-expired-dark.svg create mode 100644 artifacts/icon-family-v1/svg/time-expired-light.svg create mode 100644 artifacts/icon-family-v1/svg/time-half-dark.svg create mode 100644 artifacts/icon-family-v1/svg/time-half-light.svg create mode 100644 artifacts/icon-family-v1/svg/time-hour-dark.svg create mode 100644 artifacts/icon-family-v1/svg/time-hour-light.svg create mode 100644 artifacts/icon-family-v1/svg/time-quarter-dark.svg create mode 100644 artifacts/icon-family-v1/svg/time-quarter-hour-dark.svg create mode 100644 artifacts/icon-family-v1/svg/time-quarter-hour-light.svg create mode 100644 artifacts/icon-family-v1/svg/time-quarter-light.svg create mode 100644 artifacts/icon-family-v1/svg/time-start-dark.svg create mode 100644 artifacts/icon-family-v1/svg/time-start-light.svg create mode 100644 artifacts/icon-family-v1/svg/time-three-quarter-dark.svg create mode 100644 artifacts/icon-family-v1/svg/time-three-quarter-light.svg create mode 100644 artifacts/icon-family-v1/svg/time-unknown-dark.svg create mode 100644 artifacts/icon-family-v1/svg/time-unknown-light.svg create mode 100644 artifacts/icon-family-v1/svg/vpn-connected-dark.svg create mode 100644 artifacts/icon-family-v1/svg/vpn-connected-light.svg create mode 100644 artifacts/icon-family-v1/svg/vpn-connecting-dark.svg create mode 100644 artifacts/icon-family-v1/svg/vpn-connecting-light.svg create mode 100644 artifacts/icon-family-v1/svg/vpn-error-dark.svg create mode 100644 artifacts/icon-family-v1/svg/vpn-error-light.svg create mode 100644 artifacts/icon-family-v1/svg/vpn-network-dark.svg create mode 100644 artifacts/icon-family-v1/svg/vpn-network-light.svg create mode 100644 artifacts/icon-family-v1/svg/vpn-off-dark.svg create mode 100644 artifacts/icon-family-v1/svg/vpn-off-light.svg create mode 100644 artifacts/icon-family-v1/svg/vpn-reconnect-dark.svg create mode 100644 artifacts/icon-family-v1/svg/vpn-reconnect-light.svg create mode 100644 artifacts/icon-family-v1/svg/vpn-setup-dark.svg create mode 100644 artifacts/icon-family-v1/svg/vpn-setup-light.svg create mode 100644 artifacts/icon-family-v1/svg/vpn-unknown-dark.svg create mode 100644 artifacts/icon-family-v1/svg/vpn-unknown-light.svg create mode 100644 artifacts/icon-family-v1/svg/vpn-unlock-dark.svg create mode 100644 artifacts/icon-family-v1/svg/vpn-unlock-light.svg create mode 100644 bin/lemana-vpn-import-yandex.py create mode 100644 docs/goals/compact-menu/GOAL.md create mode 100644 docs/goals/compact-menu/PLAN.md create mode 100644 docs/goals/configured-auth-ui/GOAL.md create mode 100644 docs/goals/configured-auth-ui/PLAN.md create mode 100644 docs/goals/logging-and-config/GOAL.md create mode 100644 docs/goals/logging-and-config/PLAN.md create mode 100644 docs/goals/startup-dns-and-icons/GOAL.md create mode 100644 docs/goals/startup-dns-and-icons/PLAN.md create mode 100644 docs/goals/two-auth-modes/GOAL.md create mode 100644 docs/goals/two-auth-modes/PLAN.md create mode 100644 docs/goals/yandex-key-import/GOAL.md create mode 100644 docs/goals/yandex-key-import/PLAN.md create mode 100644 templates/bitwarden-auto.env create mode 100644 templates/keychain-auto.env create mode 100644 templates/manual-keychain.env create mode 100644 tests/auth_retry.py create mode 100644 tests/auth_settings.py create mode 100644 tests/configuration.py create mode 100644 tests/connection_runtime.py create mode 100644 tests/dns_cli.py create mode 100644 tests/dns_recovery.py create mode 100644 tests/icons.py create mode 100644 tests/logging.py create mode 100644 tests/menu.py create mode 100644 tests/session_stop.py create mode 100644 tests/yandex_import.py diff --git a/.agents/skills/lemana-vpn-operations/SKILL.md b/.agents/skills/lemana-vpn-operations/SKILL.md index 06989fe..443ba74 100644 --- a/.agents/skills/lemana-vpn-operations/SKILL.md +++ b/.agents/skills/lemana-vpn-operations/SKILL.md @@ -33,7 +33,7 @@ tail -f ~/Library/Logs/LemanaVPN-openconnect-lite.log tail -f ~/Library/Logs/LemanaVPN.log ``` -Use `vpn --manual` for SSO diagnosis before automatic mode. Use `vpn-lemanapro.sh --patch-only` when only runtime patches need to be applied. +Manual or interactive SSO checks require an explicit request in the current prompt. Within that authorization, use `vpn --manual` for SSO diagnosis before automatic mode. Use `vpn-lemanapro.sh --patch-only` when only runtime patches need to be applied. ## Update Commands @@ -59,7 +59,7 @@ vpn --configure-keychain ## Answer Format -Final answers must always include how to run, how to check, and how to update. Also state whether live VPN was tested or intentionally skipped because an existing connection should not be disturbed. +For behavior or installation changes, include relevant run, check, and update commands, and state whether live VPN was tested. For skill-only or documentation-only changes, report the result and structural checks without unrelated installation steps. ## Common Mistakes diff --git a/.agents/skills/lemana-vpn-testing/SKILL.md b/.agents/skills/lemana-vpn-testing/SKILL.md index bad0714..72b59c6 100644 --- a/.agents/skills/lemana-vpn-testing/SKILL.md +++ b/.agents/skills/lemana-vpn-testing/SKILL.md @@ -45,7 +45,7 @@ Prefer installed status when verifying what the menu-bar app will see, because ` ## Live VPN Checks -Live checks are appropriate only for changes to connection start/stop, reconnect, SSO/autofill, Bitwarden/Keychain, `openconnect-lite` patching, status JSON consumed by the app, or DNS cleanup. +Manual or interactive live checks require an explicit request in the current prompt. Relevance alone is not authorization. Live checks are appropriate only for changes to connection start/stop, reconnect, SSO/autofill, Bitwarden/Keychain, `openconnect-lite` patching, status JSON consumed by the app, or DNS cleanup. Before a live check: @@ -93,9 +93,11 @@ Real install can modify Homebrew packages, pipx packages, sudoers, `/usr/local/s ## Final Report -Report exact commands and results. Always include: +Report exact commands and results relevant to the change. For behavior or installation changes, include: - Run: command to use the changed repo/app. - Check: command to verify state or behavior. - Update: `sh install.sh` from checkout or the remote `curl ... | sh`. - Not run: especially any skipped live VPN reconnect, real install, or real uninstall. + +For skill-only or documentation-only changes, report the result and structural checks; omit unrelated run/update instructions. diff --git a/AGENTS.md b/AGENTS.md index 4f2fc11..1f109b0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -55,11 +55,11 @@ swift build -c release --package-path app git diff --check ``` -Run a live VPN check only when the change affects real connection behavior, credential flow, SSO/autofill, status reporting, reconnect, or DNS cleanup, and only after checking current status. If VPN is already connected, do not start a second session; report that live reconnect was intentionally skipped unless the user explicitly asks for it. +Manual or interactive live checks require an explicit request in the current prompt. Run a live VPN check only when the change affects real connection behavior, credential flow, SSO/autofill, status reporting, reconnect, or DNS cleanup, and only after checking current status. If VPN is already connected, do not start a second session; report that live reconnect was intentionally skipped unless the user explicitly asks for it. ## Answer Contract -Every final answer for this repository must include: +For behavior or installation changes, the final answer includes the relevant items below. For skill-only or documentation-only changes, report the result and structural checks without unrelated run/update steps: - What changed, with file references when useful. - How to run it. diff --git a/README.md b/README.md index b05e1a7..a482d24 100644 --- a/README.md +++ b/README.md @@ -1,621 +1,390 @@ # Lemana VPN -CLI-установка корпоративного VPN `vpn.lemanapro.ru` для macOS. +macOS-пакет для подключения к корпоративному VPN `vpn.lemanapro.ru`. -**По умолчанию:** ручной вход без сохранения паролей. Откроется окно корпоративного входа, а логин, пароль и одноразовый код вводятся вручную. Bitwarden, Touch ID, сохранение пароля, подстановка 2FA и автоматический вход включаются только явно. +В приложении два способа входа: -**Режимы входа:** `manual` ничего не сохраняет и ничего не подставляет; `saved-login` хранит LDAP логин/пароль в macOS Keychain и оставляет одноразовый код ручным; `saved-totp` дополнительно хранит постоянный код настройки 2FA; `auto` запускается только явно через `vpn-auto`/`--auto`. +- **Вручную**: логин и пароль берутся с этого Mac, одноразовый код вводится вручную в видимом окне. +- **Автоматически**: данные подставляются и форма отправляется в скрытом браузере. Источник выбирается отдельно: **Ключ на этом Mac** или **Bitwarden**. -Репозиторий собирает в один воспроизводимый пакет то, что раньше было ручной локальной настройкой: +Кнопка **Подключить** всегда использует сохранённую настройку. Изменение способа входа не запускает VPN и применяется при следующем подключении. Свежая установка по умолчанию выбирает ручной ввод кода. -- `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 --status 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/domain пароль; -- service `openconnect-lite`, account `totp/` — постоянный код настройки 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 +Интерактивный установщик сначала предлагает способ входа, затем источник для автоматического режима: + +```text +Какой режим использовать? + + 1) Ручной вход: запомнить логин и пароль на этом Mac (рекомендуется) + Логин и пароль подставятся из macOS Keychain. Одноразовый код вводится руками каждый раз. + + 2) Автоматический вход + Пароль и код подставляются автоматически, форма отправляется без ручного ввода. + +Источник данных: 1) Ключ на этом Mac, 2) Bitwarden [1/2, Enter=1] ``` -Режимы подключения: - -- `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="" -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 install.sh --non-interactive --mode manual-keychain --configure-login +sh install.sh --non-interactive --mode keychain-auto --import-yandex-key +sh install.sh --non-interactive --mode bitwarden-auto ``` -Для режима с сохранённым логином и паролем: +Проверить действия без изменений: ```sh -LEMANA_VPN_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" +sh install.sh --dry-run --non-interactive --mode manual-keychain +sh install.sh --dry-run --non-interactive --mode bitwarden-auto ``` -Если LDAP username не указан при установке, `vpn` спросит его при первом интерактивном запуске в Terminal и сохранит в `~/.config/lemana-vpn/env`. Для неинтерактивной установки можно указать его сразу: +## Ручной Режим + +По умолчанию `manual-keychain` хранит только LDAP username/password: + +- service `openconnect-lite`, account `` - LDAP password; +- TOTP/current 6-digit code не сохраняется и не требуется. + +Настроить или обновить логин и пароль: ```sh -curl -fsSL https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main/install.sh \ - | sh -s -- --username +vpn --configure-login ``` -## Bitwarden item +Из меню LemanaVPN.app доступна команда `Логин и пароль…`; она открывает Terminal и запускает тот же CLI-путь, чтобы пароль вводился в нормальном TTY. -Нужна запись: - -- название: `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 +vpn ``` -Патчи: +Ожидаемое поведение: откроется видимое окно входа, логин и пароль подставятся, одноразовый код вводится руками, submit не нажимается автоматически. -| Патч | Что меняет | Зачем | -| --- | --- | --- | -| `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 сохраняет оригинальный файл: +В Яндекс Ключе (Яндекс ID) откройте **Настройки → Резервная копия данных → Сохранить в файл** и перенесите файл на Mac. Это штатный [локальный экспорт Яндекса](https://yandex.ru/support/id/ru/authorization/twofa-copy). Он содержит секреты всех записей: не отправляйте его в чат и не загружайте в онлайн-конвертеры. + +В обычном установщике есть отдельный вопрос об импорте. Запустить установку сразу с этим шагом: ```sh -~/.config/lemana-vpn/patch-backups/webengine_process.py.before-lemana-vpn +sh install.sh --mode keychain-auto --import-yandex-key ``` -Откат патчей выполняет uninstall script. Если backup отсутствует, автоматического rollback нет: значит файл был уже патчен старой ручной установкой или `openconnect-lite` переустановили после backup. - -## Диагностика - -Проверить установку: +Для уже установленного CLI после обновления: ```sh -command -v vpn-lemanapro.sh -openconnect --version -~/.local/bin/openconnect-lite --help -sudo -n /usr/local/sbin/lemana-vpn-dns-cleanup +vpn --configure-login # если логин и пароль ещё не сохранены +vpn --import-yandex-key vpn --status ``` -Обычный `vpn` теперь пишет путь к подробному логу `openconnect-lite`: +Мастер спросит путь к файлу, покажет имена записей и предложит выбрать запись Lemana/VPN. Перед сохранением он покажет LDAP-аккаунт назначения и попросит текущий код с телефона. Проверка выполняется локально; введённый код скрыт. LDAP-логин в настройках CLI и профиле SSO должен совпадать. + +После успешной проверки только выбранный секрет сохраняется в macOS Keychain: service `openconnect-lite`, account `totp/`. В `env` выбирается `keychain-auto`: автоматический вход с ключом на этом Mac. Пароль остаётся прежним. Команда `vpn` подставит логин, пароль и код и отправит форму в скрытом браузере. Bitwarden для этого не нужен. Импорт не запускает VPN. + +Поддерживается локальный JSON-экспорт (`key_backup` или `key_backup.txt`), TOTP / SHA1 / 6 цифр / 30 секунд. Другие алгоритмы, HOTP и собственные коды аккаунта Яндекса отклоняются. Лимиты импортёра: файл до 4 МиБ, до 1000 записей. Формат проверен по [импортёру GNOME Authenticator](https://world.pages.gitlab.gnome.org/Authenticator/src/authenticator/backup/yandex.rs.html); облачные копии и QR-коды этот мастер не читает. + +Отмена или неверный код ничего не сохраняют. При ошибке включения настройки импортёр пытается вернуть прежнюю запись Keychain и сообщает, если откат не удался. Исходный файл не копируется и автоматически не удаляется. При выключении компьютера или принудительном завершении процесса между записями проверьте состояние через `vpn --status` и при необходимости повторите импорт. + +Чтобы снова вводить код вручную, выберите «Вручную» в меню или выполните `vpn --set-auth=manual`. Сохранённый секрет останется в Keychain. `vpn --manual-full` по-прежнему отключает любую подстановку. Обновление сохраняет выбранную настройку; режим `bitwarden-auto` использует свой прежний путь. + +## Автоматический вход через Bitwarden + +`bitwarden-auto` использует Bitwarden как источник данных: + +- Bitwarden item: `LM LDAP`; +- Bitwarden username - LDAP username; +- Bitwarden password - LDAP/domain password, не master password от vault; +- Bitwarden TOTP field - permanent 2FA setup secret или `otpauth://...`, не текущие 6 цифр; +- Touch ID helper может открыть master password для Bitwarden; +- runtime sync кладёт username в config, а пароль и permanent 2FA secret в macOS Keychain для `openconnect-lite`. + +В этом режиме Lemana VPN не спрашивает LDAP username/password вручную. Если `~/.config/lemana-vpn/env` содержит пустой `LEMANA_VPN_USERNAME=""`, это нормально: username заполнится из `LM LDAP` после успешного Bitwarden unlock/sync. + +Подключиться: ```sh -~/Library/Logs/LemanaVPN-openconnect-lite.log +vpn ``` -Если после `Connecting to VPN (lemanapro)...` SSO завис или не видно, что происходит, смотри этот файл: +Разово запустить вход через Bitwarden из CLI: ```sh +vpn-auto +vpn bitwarden-auto +``` + +Если Bitwarden не залогинен: + +```sh +bw login +``` + +Если автоматический вход не проходит, сначала проверь статус и логи: + +```sh +vpn --status 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-патчи без подключения: +Меню приложения открывается в компактном окне. Пункт **Импорт из Яндекс Ключа…** запускает существующий мастер в Terminal; приложение не читает секреты. В меню всегда видны сохранённый способ входа и источник. Стрелки с разовыми режимами у «Подключить» нет; настройки изменяются отдельными переключателями. Во время сохранения нельзя запустить подключение или второй запрос изменения. + +В разделе **Значок в строке меню** можно выбрать: + +- **Щит**: значок 16 pt с яркой заливкой оставшегося времени и прогрессом по контуру; вариант по умолчанию. +- **Кольцо**: круг с такой же заливкой оставшегося времени и прогрессом по контуру. +- **Часы**: щит с циферблатом и движущейся стрелкой. +- **Время**: щит и компактное оставшееся время `H:MM`. + +Выбор сохраняется между запусками, в том числе ранее выбранные кольцо, часы и время. Значки зелёные, пока остаётся больше часа; янтарные в последний час, красные в последние 15 минут. Нейтральная подложка и более плотная цветная заливка делают прогресс различимым в строке меню. Точное время видно в меню и подсказке значка. Начало и конец берутся из CLI, фиксированной длительности нет. Со старым CLI начало отсчитывается от первого события подключения. Если срок неизвестен или некорректен, прогресс не выдумывается. Истечение таймера само по себе не запускает новое подключение. Значки состояний, действий и источников входа используют единый векторный набор. + +Индикаторы «Щит» и «Кольцо» начинают с полной яркой заливки. По мере расхода времени яркая часть уменьшается сверху вниз, а израсходованная остаётся тусклой и видимой. + +«Подключено» появляется после выдачи адреса туннеля, независимо от наличия срока сессии. CLI понимает оба формата даты OpenConnect, включая числовой часовой пояс. Срок может прийти до или после адреса; последующие сообщения не сдвигают начало сессии. До получения срока меню показывает «Срок сессии неизвестен». `vpn --status` также различает подключение и переподключение. + +### Переподключение и защита входа + +В автоматическом режиме (Keychain или Bitwarden) после завершения поднятого туннеля CLI проверяет остановку процессов и восстановление DNS, затем повторяет подключение через 5 секунд. При неудачных попытках до поднятия туннеля допускаются пять повторов с паузами 5, 10, 20, 40 и 60 секунд. Приложение отображает эти состояния; собственного второго цикла повторов у него нет. Ручной режим и отмена входа не запускают автоматические повторы. + +Каждый этап автоматического входа отправляется один раз: переход от пароля к одноразовому коду разрешён. Видимая ошибка формы или повторный запрос уже отправленного этапа останавливает вход и все автоматические повторы. Ошибка остаётся в меню после очистки DNS. Проверьте пароль и код, затем запустите подключение вручную. Защита не вводит локальную блокировку по времени и не меняет ручную отправку формы. + +Если проверка доступности обнаружит зависший туннель, приложение просит helper завершить только `openconnect` своей сессии. Запоздалый запрос не прерывает уже восстановившийся туннель. CLI остаётся работать и выполняет ту же проверку DNS перед повтором. При активном чужом VPN, незавершённых процессах или ошибке восстановления новая попытка не запускается. «Отключить» и «Выход» отменяют и ожидающий повтор. + +### Восстановление DNS после перезагрузки + +При запуске приложение проверяет, не остались ли настройки DNS после аварийно завершённого VPN. Перед подключением root-owned helper записывает исходные DNS сетевых сервисов и DNS, выданные VPN, в `/var/db/lemana-vpn-dns`. После обычного отключения или следующего запуска он возвращает прежние значения, включая пользовательские DNS; для автоматических настроек возвращается DHCP. + +После «Отключить» root-helper отправляет `TERM` только `openconnect` зарегистрированной сессии. Проверяются пользователь, идентификатор сессии, загрузка системы, PID и время запуска; чужие VPN не останавливаются. До появления туннеля отменяются только пользовательские процессы входа этой сессии. Запись об отмене не позволяет запоздавшему дочернему процессу настроить сеть. + +Меню показывает «Отключение», пока завершаются процессы VPN и проверяется восстановление DNS. Если дочерние процессы ещё выходят, CLI повторяет проверку до 30 раз с интервалом в секунду. «Выход» и Cmd+Q ждут завершения отключения и проверки DNS. Повторное нажатие не прерывает очистку. При ошибке или ожидании дольше 45 секунд приложение остаётся открытым с кнопкой «Повторить отключение»; принудительный `KILL` не применяется. Для этого должны быть обновлены вместе CLI, helper и приложение через `sh install.sh`. + +Восстановление не запускает VPN, не трогает активное подключение и не сбрасывает произвольные адреса `10.x`. Проверяются процессы, сохранённая сетевая конфигурация и совпадение текущих DNS с записанными. Изменённые пользователем DNS сохраняются. Ошибка восстановления видна в меню; «Обновить статус» повторяет проверку. Пока проверка идёт или требуется исправление, «Подключить» недоступна. ```sh -curl -fsSL https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main/install.sh | sh -vpn-lemanapro.sh --patch-only +vpn --repair-dns # Проверить и восстановить без подключения +vpn --repair-dns --json # Результат для приложения ``` -Если лог падает раньше браузера с `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. +`vpn-fix-dns` вызывает ту же проверку. Обычный `sh install.sh` обновляет helper, CLI и приложение; без обновления старого helper новое подключение заблокировано. Функция восстановления требует установленного правила sudoers и работает без запроса пароля. -Если SSO ломается после обновления `openconnect-lite`, запусти: +Настройки подключения, сделанного **до этого обновления**, ещё не имеют сохранённого исходного DNS. Такие остатки автоматически не удаляются: по одному адресу нельзя отличить настройки VPN от пользовательских. Если DNS уже зависли от старой версии, сначала нужно один раз вернуть обычные настройки DNS, затем подключаться обновлённой версией. После этого защита сохраняет их для будущих восстановлений. При смене сетевой конфигурации (Location) незавершённая запись сохраняется до возврата к ней; новая сессия не перезаписывает её. ```sh -vpn-debug +vpn --status +vpn --status --json ``` -Если нужно самому посмотреть форму Keycloak, но оставить подстановку LDAP/TOTP: +Human output показывает активный режим: + +```text +Modules: ✅ core=ok, 🔐 mode=manual-keychain, ⏭️ bitwarden=off, ⏭️ touchid=off, ... +VPN disconnected +``` + +JSON содержит публичный mode contract: + +```json +{ + "modules": { + "mode": { + "id": "manual-keychain", + "label": "Вручную", + "ready": false, + "setup_hint": "Настройте логин и пароль: vpn --configure-login" + }, + "auth": { + "mode": "manual", + "source": "keychain", + "auto_source": "keychain", + "label": "Вручную", + "detail": "Логин и пароль с этого Mac, код вводится вручную", + "ready": false, + "setup_hint": "Настройте логин и пароль: vpn --configure-login" + } + } +} +``` + +Swift-приложение не вычисляет режим само. Оно читает `vpn --status --json` и сохраняет выбор через CLI. Унаследованные от запускающего shell переменные режима не подменяют настройку приложения. + +## Что Ставится + +| Путь | Назначение | +| --- | --- | +| `~/bin/vpn-lemanapro.sh` | основной CLI | +| `~/bin/uninstall-lemana-vpn.sh` | локальный uninstall helper | +| `~/bin/keychain-fingerprint` | optional Touch ID helper для Bitwarden | +| `~/Applications/LemanaVPN.app` | menu-bar приложение | +| `~/Library/LaunchAgents/ru.dokops.LemanaVPN.plist` | автозапуск приложения | +| `~/.config/lemana-vpn/env` | активный выбранный режим | +| `~/.config/openconnect-lite/config.toml` | профиль SSO и Keycloak autofill rules | +| `/usr/local/sbin/lemana-vpn-dns-cleanup` | root-owned DNS cleanup wrapper | +| `/var/db/lemana-vpn-dns` | Защищённый журнал исходных DNS и запись владельца VPN-сессии | +| `/etc/sudoers.d/lemana-vpn-openconnect` | `NOPASSWD` только для `openconnect` | +| `/etc/sudoers.d/lemana-vpn-dns` | `NOPASSWD` только для DNS cleanup wrapper | + +Source-of-truth профили в репозитории: + +- `templates/manual-keychain.env` +- `templates/keychain-auto.env` +- `templates/bitwarden-auto.env` + +Installer рендерит один из них в `~/.config/lemana-vpn/env`. + +## Настройки и журналы + +Пользовательские параметры находятся в `~/.config/lemana-vpn/env`. Это shell-файл: используйте простые присваивания в кавычках, без команд. Пароли и код настройки 2FA остаются в Keychain. + +| Параметр | Значение и назначение | +| --- | --- | +| `LEMANA_VPN_MODE` | `manual-keychain`, `keychain-auto` или `bitwarden-auto` | +| `LEMANA_VPN_BW_ITEM` | Имя записи Bitwarden, по умолчанию `LM LDAP` | +| `LEMANA_VPN_USE_TOUCHID` | `1` или `0`; используется в `bitwarden-auto` | +| `LEMANA_VPN_AUTO_SOURCE` | Последний источник автоматического входа: `keychain` или `bitwarden` | +| `LEMANA_VPN_LOG_MAX_BYTES` | Размер каждого файла журнала в байтах, по умолчанию `5242880` (5 МиБ) | +| `LEMANA_VPN_CONNECT_WAIT_SECONDS` | Интервал сообщения об ожидании SSO, по умолчанию `20` секунд | + +Например, чтобы уменьшить журналы до 1 МиБ на файл, добавьте или измените строку: ```sh -vpn --manual +LEMANA_VPN_LOG_MAX_BYTES="1048576" ``` -В этом режиме браузер видимый, `openconnect-lite` заполняет поля из Keychain/Bitwarden, но не нажимает submit. +Лимит — целое число от `1` до `999999999`. CLI применяет его при следующем запуске; приложение получает его из CLI при обновлении статуса. У каждого журнала в `~/Library/Logs` остаются текущий файл и один предыдущий `.1`: `LemanaVPN.log` и `LemanaVPN-openconnect-lite.log`. По умолчанию это до 20 МиБ суммарно. Ограничение действует при каждой записи, в том числе внутри долгого сеанса; от старого большого файла сохраняется только ограниченный хвост. Само изменение исходников существующие журналы не очищает — нужен обновлённый CLI и приложение. -Если нужно проверить SSO полностью вручную, без подстановки LDAP-пароля и TOTP: +Обновление сохраняет выбранный режим, логин, имя записи Bitwarden, Touch ID и дополнительные параметры в `env`. Флаги установщика имеют приоритет над переменными окружения, затем используются сохранённые значения и значения по умолчанию. Для CLI явно заданные переменные окружения режима, логина, Bitwarden, Touch ID и лимита журнала также имеют приоритет над `env`. + +Существующий `~/.config/openconnect-lite/config.toml` сохраняет адрес, профиль и правила SSO; установщик обновляет только имя пользователя в `[credentials]`. Изменения шаблона SSO при обновлении автоматически не заменяют ваш профиль. Для логина и пароля используйте `vpn --configure-login`. + +## Сохранение способа входа из CLI + +```sh +vpn --set-auth=manual # ручной ввод кода +vpn --set-auth=keychain # автоматический вход с ключом на этом Mac +vpn --set-auth=bitwarden # автоматический вход через Bitwarden +vpn --set-auth=auto # последний выбранный автоматический источник +``` + +Команды только сохраняют настройку. Пароль и секреты не считываются и не изменяются, подключение не начинается. Готовность выбранного источника и нужный шаг настройки видны в `vpn --status --json`. + +Импорт и синхронизация Bitwarden используют существующую запись Keychain `totp/`. Поэтому название «Ключ на этом Mac» обозначает место хранения, а не гарантированное происхождение ключа. + +## Совместимость + +Ранее сохранённое сочетание `manual-keychain` + `LEMANA_VPN_LOCAL_OTP=1` теперь означает **полный автоматический вход** и при обновлении переводится в `keychain-auto`. Для ручной отправки и ввода кода выберите «Вручную» или `vpn --set-auth=manual`. Явные `vpn --manual` и `vpn --manual-full` принудительно отключают автоматический код независимо от сохранённого режима. + +Старые команды оставлены как shims, чтобы существующие shell привычки не ломались: + +```sh +vpn-auto # bitwarden-auto +vpn --auto # bitwarden-auto +vpn-manual # manual-keychain +vpn --manual # manual-keychain +vpn --saved-login # manual-keychain +``` + +Диагностический fallback без подстановки полей остаётся, но это не отдельный режим установки: ```sh vpn --manual-full +vpn-manual-full ``` -Этот режим не требует заранее сохранённого LDAP username/password/TOTP и не запускает Bitwarden/Keychain preflight. +Он нужен только когда надо проверить, что проблема не в autofill. -Если установка падает на строке `install: /usr/local/sbin/...: No such file or directory`, значит на машине не было `/usr/local/sbin`. Актуальный `install.sh` создаёт эту директорию сам; достаточно повторить установку свежей командой `curl`. +## Обновление -CLI перед подключением патчит `openconnect-lite`: +Из checkout: -- `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 +sh install.sh +vpn --status +open ~/Applications/LemanaVPN.app +``` + +Удалённо: + +```sh +curl -fsSL https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main/install.sh | sh +``` + +После изменения Swift app важно убедиться, что установленный бинарь обновился: + +```sh +shasum app/.build/release/LemanaVPN ~/Applications/LemanaVPN.app/Contents/MacOS/LemanaVPN +strings ~/Applications/LemanaVPN.app/Contents/MacOS/LemanaVPN | rg 'manual-keychain|bitwarden-auto|import-yandex-key' +``` ## Удаление -Рекомендуемый способ: - ```sh -curl -fsSL https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main/uninstall.sh | sh +~/bin/uninstall-lemana-vpn.sh ``` -Или локально: +Посмотреть действия без удаления: ```sh -uninstall-lemana-vpn.sh +~/bin/uninstall-lemana-vpn.sh --dry-run ``` -Что делает 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`. - -Опциональные режимы: +Для проверок нужен Python 3.11+ (`tomllib`), для изолированного исполнения JavaScript автозаполнения — Node.js. Браузер и настоящее подключение тесты не запускают; Node.js самому VPN не нужен. ```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 -n install.sh +sh -n uninstall.sh +bash -n bin/vpn-lemanapro.sh +sh -n tests/smoke.sh +tests/smoke.sh +python3 tests/configuration.py +python3 tests/logging.py +python3 tests/menu.py +python3 tests/dns_cli.py +python3 tests/dns_recovery.py +python3 tests/session_stop.py +python3 tests/connection_runtime.py +python3 tests/auth_retry.py +python3 tests/auth_settings.py +"${LEMANA_VPN_OC_PYTHON:-$HOME/.local/pipx/venvs/openconnect-lite/bin/python}" tests/yandex_import.py +swift build -c release --package-path app +git diff --check ``` -Ручной вариант, если нужен полный контроль: +Live VPN проверяется только после статуса: ```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 +vpn --status ``` -Из `~/.zshrc` удалить блок: +Если VPN уже connected, connecting или reconnecting, не запускай вторую сессию. Смотри логи: ```sh -# >>> lemana-vpn -... -# <<< lemana-vpn +tail -f ~/Library/Logs/LemanaVPN-openconnect-lite.log +tail -f ~/Library/Logs/LemanaVPN.log ``` diff --git a/app/Sources/LemanaVPN/BoundedLog.swift b/app/Sources/LemanaVPN/BoundedLog.swift new file mode 100644 index 0000000..dfc7406 --- /dev/null +++ b/app/Sources/LemanaVPN/BoundedLog.swift @@ -0,0 +1,38 @@ +import Foundation + +/// One current file and one bounded archive. The owning process serializes writes. +struct BoundedLog { + let url: URL + var maxBytes = 5 * 1024 * 1024 + + func append(_ line: String) throws { + let files = FileManager.default + try files.createDirectory(at: url.deletingLastPathComponent(), withIntermediateDirectories: true) + if !files.fileExists(atPath: url.path) { + guard files.createFile(atPath: url.path, contents: nil, attributes: [.posixPermissions: 0o600]) else { + throw CocoaError(.fileWriteUnknown) + } + } + try files.setAttributes([.posixPermissions: 0o600], ofItemAtPath: url.path) + let handle = try FileHandle(forUpdating: url) + defer { try? handle.close() } + let size = try handle.seekToEnd() + let data = Data(line.utf8).suffix(maxBytes) + let archive = url.appendingPathExtension("1") + var archiveSize: UInt64 = 0 + if files.fileExists(atPath: archive.path) { + try files.setAttributes([.posixPermissions: 0o600], ofItemAtPath: archive.path) + archiveSize = (try files.attributesOfItem(atPath: archive.path)[.size] as? NSNumber)?.uint64Value ?? 0 + } + if size + UInt64(data.count) > UInt64(maxBytes) || archiveSize > UInt64(maxBytes) { + try handle.seek(toOffset: size > UInt64(maxBytes) ? size - UInt64(maxBytes) : 0) + let tail = try handle.read(upToCount: maxBytes) ?? Data() + guard files.createFile(atPath: archive.path, contents: tail, attributes: [.posixPermissions: 0o600]) else { + throw CocoaError(.fileWriteUnknown) + } + try handle.truncate(atOffset: 0) + try handle.seek(toOffset: 0) + } + try handle.write(contentsOf: data) + } +} diff --git a/app/Sources/LemanaVPN/LemanaVPNApp.swift b/app/Sources/LemanaVPN/LemanaVPNApp.swift index 15ac663..40c8aa9 100644 --- a/app/Sources/LemanaVPN/LemanaVPNApp.swift +++ b/app/Sources/LemanaVPN/LemanaVPNApp.swift @@ -3,190 +3,398 @@ import SwiftUI @main struct LemanaVPNApp: App { - @StateObject private var vpnManager = VPNManager() + @NSApplicationDelegateAdaptor(LemanaAppDelegate.self) private var appDelegate + @AppStorage("menuBarIndicatorStyle") private var indicatorStyle = VPNIndicatorStyle.shield + + private var vpnManager: VPNManager { appDelegate.vpnManager } var body: some Scene { MenuBarExtra { - VPNMenuView(vpnManager: vpnManager) + VPNMenuView(vpnManager: vpnManager, indicatorStyle: $indicatorStyle) } label: { - StatusBarLabel(vpnManager: vpnManager) + StatusBarLabel(vpnManager: vpnManager, style: indicatorStyle) } + .menuBarExtraStyle(.window) + } +} + +@MainActor +final class LemanaAppDelegate: NSObject, NSApplicationDelegate { + let vpnManager = VPNManager() + private var terminationPending = false + + func applicationShouldTerminate(_ sender: NSApplication) -> NSApplication.TerminateReply { + guard vpnManager.needsDisconnectBeforeQuit else { return .terminateNow } + if !terminationPending { + terminationPending = true + vpnManager.quit { [weak self] success in + self?.terminationPending = false + sender.reply(toApplicationShouldTerminate: success) + } + } + return .terminateLater + } +} + +private extension SessionTiming.Urgency { + var color: NSColor { + switch self { + case .normal: return .systemGreen + case .warning: return .systemOrange + case .critical: return .systemRed + case .unknown: return .secondaryLabelColor + } + } +} + +private extension VPNManager { + var statusIcon: VPNIcon { + if state == .disconnecting { return .connecting } + if isCheckingConnection { return .connecting } + if connectionCheckFailed { return .setup } + if isExternallyActive { return .unknown } + switch state { + case .disconnected: + if moduleStatusSystemImage == "exclamationmark.triangle" { return .setup } + if moduleStatusSystemImage == "questionmark.circle" { return .unknown } + return .off + case .unlocking: return .unlock + case .connecting: return .connecting + case .disconnecting: return .connecting + case .connected: + if !tunnelHealthy { return .network } + return sessionTiming.remaining(at: Date()) == 0 ? .expired : .connected + case .reconnecting: return .reconnect + case .error: return .error + } + } +} + +private struct VPNIconView: View { + @Environment(\.colorScheme) private var colorScheme + let icon: VPNIcon + + var body: some View { + Image(nsImage: VPNIcons.image(icon, dark: colorScheme == .dark)) + .frame(width: 16, height: 16) + .accessibilityHidden(true) } } struct StatusBarLabel: View { @ObservedObject var vpnManager: VPNManager + @Environment(\.colorScheme) private var colorScheme + let style: VPNIndicatorStyle var body: some View { HStack(spacing: 4) { - Image(systemName: iconName) - if !vpnManager.statusBarTitle.isEmpty { - Text(vpnManager.statusBarTitle) - .monospacedDigit() + if case .connected = vpnManager.state, vpnManager.tunnelHealthy { + Image(nsImage: VPNIcons.sessionImage( + style: style, + progress: vpnManager.sessionTiming.progress(at: Date()), + urgency: vpnManager.sessionTiming.urgency(at: Date()), + dark: colorScheme == .dark + )) + .renderingMode(.original) + .frame(width: 16, height: 16) + if style == .time, !vpnManager.remainingTime.isEmpty { + Text(vpnManager.remainingTime) + .font(.system(size: 11, weight: .medium, design: .monospaced)) + .fixedSize() + } + } else { + VPNIconView(icon: vpnManager.statusIcon) } } + .accessibilityElement(children: .ignore) + .accessibilityLabel(accessibilityText) + .help(accessibilityText) } - private var iconName: String { + private var accessibilityText: String { + if vpnManager.state == .disconnecting { return "Lemana VPN отключается и восстанавливает DNS" } + if vpnManager.isCheckingConnection || vpnManager.connectionCheckFailed || vpnManager.isExternallyActive, + let message = vpnManager.connectionCheckMessage { return "Lemana VPN: \(message)" } switch vpnManager.state { - case .disconnected: - if vpnManager.moduleStatusSystemImage == "exclamationmark.triangle" { - return "exclamationmark.shield" - } - if vpnManager.moduleStatusSystemImage == "questionmark.circle" { - return "questionmark.circle" - } - return "shield.slash" - case .unlocking, .connecting: - return "shield.lefthalf.filled" case .connected: - return vpnManager.tunnelHealthy ? "checkmark.shield" : "exclamationmark.shield" - case .reconnecting: - return "arrow.trianglehead.2.clockwise" - case .error: - return "exclamationmark.shield" + return "Lemana VPN: \(vpnManager.tunnelHealthy ? "подключён" : "проблема соединения"), \(vpnManager.sessionTiming.remainingLabel(at: Date()).lowercased())" + case .disconnected: return "Lemana VPN отключён" + case .connecting: return "Lemana VPN подключается" + case .disconnecting: return "Lemana VPN отключается и восстанавливает DNS" + case .unlocking: return "Lemana VPN ожидает вход в Bitwarden" + case .reconnecting: return "Lemana VPN переподключается" + case .error(let message): return "Lemana VPN: \(message)" } } } struct VPNMenuView: View { @ObservedObject var vpnManager: VPNManager + @Binding var indicatorStyle: VPNIndicatorStyle var body: some View { - switch vpnManager.state { - case .disconnected: - disconnectedMenu - case .unlocking(let tier): - unlockingMenu(tier: tier) - case .connecting: - connectingMenu - case .connected(let ip, _, let remainingSec): - connectedMenu(ip: ip, remainingSec: remainingSec) - case .reconnecting(let attempt): - reconnectingMenu(attempt: attempt) - case .error(let message): - errorMenu(message: message) - } - - Divider() - Label(vpnManager.moduleSummary, systemImage: vpnManager.moduleStatusSystemImage) - .disabled(true) - Button("Обновить статус модулей") { - vpnManager.refreshStatus() - } - Button("Изменить логин и пароль") { - vpnManager.configureLogin() - } - Divider() - Button("Открыть логи") { - let logPath = FileManager.default.homeDirectoryForCurrentUser - .appendingPathComponent("Library/Logs/LemanaVPN.log") - NSWorkspace.shared.open(logPath) - } - Button("Выход") { - vpnManager.quit() - NSApplication.shared.terminate(nil) - } - .keyboardShortcut("q") - } - - private var disconnectedMenu: some View { - Group { - Label("VPN отключён", systemImage: "circle") - .disabled(true) - Label(vpnManager.installModeLabel, systemImage: "slider.horizontal.3") - .disabled(true) - if let setupHint = vpnManager.installSetupHint { - Label(setupHint, systemImage: "info.circle") - .disabled(true) - } - Divider() - ForEach(vpnManager.availableLaunchModes) { mode in - Button(mode.menuTitle) { - vpnManager.connect(mode: mode) + VStack(alignment: .leading, spacing: 0) { + HStack { + Text("Lemana VPN").fontWeight(.semibold) + Spacer(minLength: 8) + HStack(spacing: 5) { + VPNIconView(icon: vpnManager.statusIcon) + Text(statusTitle).font(.system(size: 11)).foregroundColor(statusColor) } } + .padding(.bottom, 10) + + connectionDetails.padding(.bottom, 9) + connectionActions.padding(.bottom, 3) + separator + authenticationSettings + if let hint = vpnManager.installSetupHint { warning(hint) } + ForEach(moduleWarnings, id: \.self) { warning($0) } + if let error = additionalError { warning(error) } + + separator + menuButton("Импорт из Яндекс Ключа…", image: .importKey) { + vpnManager.importYandexKey() + } + .help("Мастер импорта откроется в Terminal") + .disabled(!vpnManager.canConfigureCredentials) + menuButton("Логин и пароль…", image: .password) { vpnManager.configureLogin() } + .disabled(!vpnManager.canConfigureCredentials) + + separator + Text("Значок в строке меню") + .font(.system(size: 11)) + .foregroundColor(.secondary) + .padding(.bottom, 6) + Picker("Значок в строке меню", selection: $indicatorStyle) { + ForEach(VPNIndicatorStyle.allCases) { style in Text(style.title).tag(style) } + } + .labelsHidden() + .pickerStyle(.segmented) + .controlSize(.small) + .padding(.bottom, 3) + + separator + menuButton("Открыть логи", image: .logs) { + let url = FileManager.default.homeDirectoryForCurrentUser.appendingPathComponent("Library/Logs/LemanaVPN.log") + NSWorkspace.shared.open(url) + } + HStack { + Button { vpnManager.refreshConnectionStatus() } label: { + iconLabel("Обновить статус", icon: .refresh) + } + .disabled(vpnManager.isCheckingConnection || vpnManager.isSavingAuth) + Spacer() + Button { + NSApplication.shared.terminate(nil) + } label: { + iconLabel("Выход", icon: .quit) + } + .keyboardShortcut("q") + } + .buttonStyle(.plain) + .font(.system(size: 11)) + .foregroundColor(.secondary) + .padding(.top, 7) } + .font(.system(size: 13)) + .padding(12) + .frame(width: 298) + .background(Color(nsColor: .windowBackgroundColor)) + .onAppear { vpnManager.refreshStatus() } } - private func unlockingMenu(tier: String) -> some View { - Group { - Label("Bitwarden: \(tier)...", systemImage: "key") - .disabled(true) - Divider() - Button("Отменить") { - vpnManager.disconnect() + @ViewBuilder private var authenticationSettings: some View { + if let auth = vpnManager.moduleStatus?.auth { + Text("Способ входа") + .font(.system(size: 11)).foregroundColor(.secondary).padding(.bottom, 6) + Picker("Способ входа", selection: Binding( + get: { auth.mode }, + set: { vpnManager.setAuth($0) } + )) { + iconLabel("Вручную", icon: .manual).tag("manual") + iconLabel("Автоматически", icon: .auto).tag("auto") + } + .pickerStyle(.segmented) + .labelsHidden() + .controlSize(.small) + .disabled(!vpnManager.canSetAuth) + if auth.mode == "auto" { + Picker("Источник", selection: Binding( + get: { auth.auto_source }, + set: { vpnManager.setAuth($0) } + )) { + iconLabel("Ключ на этом Mac", icon: .local).tag("keychain") + iconLabel("Bitwarden", icon: .vault).tag("bitwarden") + } + .pickerStyle(.menu) + .controlSize(.small) + .padding(.top, 7) + .disabled(!vpnManager.canSetAuth) + } + Text(vpnManager.isSavingAuth ? "Сохраняем настройку…" : auth.detail) + .font(.system(size: 11)).foregroundColor(.secondary).fixedSize(horizontal: false, vertical: true) + .padding(.top, 6) + if vpnManager.isRunning { + Text("Изменения применятся при следующем подключении") + .font(.system(size: 11)).foregroundColor(.secondary).padding(.top, 4) + } + } else { + Text(vpnManager.installModeLabel).font(.system(size: 11)).foregroundColor(.secondary) + if !vpnManager.isCheckingConnection { + warning("Обновите CLI Lemana VPN, чтобы настраивать способ входа здесь.") } } } - private var connectingMenu: some View { - Group { - Label("Подключение...", systemImage: "circle.dotted") - .disabled(true) - Divider() - Button("Отменить") { - vpnManager.disconnect() - } - } - } - - private func connectedMenu(ip: String, remainingSec: Int) -> some View { - let hours = remainingSec / 3600 - let mins = (remainingSec % 3600) / 60 - - return Group { - Label("VPN подключён", systemImage: "circle.fill") - .disabled(true) - if !vpnManager.tunnelHealthy { - Label("Проблемы с подключением", systemImage: "exclamationmark.triangle") - .disabled(true) + @ViewBuilder private var connectionDetails: some View { + switch vpnManager.state { + case .connected(let ip, _, _): + HStack(alignment: .firstTextBaseline) { + Text(vpnManager.sessionTiming.remainingLabel(at: Date())).monospacedDigit() + Spacer(minLength: 6) + if let expiry = vpnManager.sessionTiming.expiresAt, vpnManager.sessionTiming.remaining(at: Date()) != nil { + Text("до \(expiry.formatted(date: .omitted, time: .shortened))") + .font(.system(size: 11)).foregroundColor(.secondary) + } } if !ip.isEmpty { - Text("IP: \(ip)") - .foregroundColor(.secondary) + HStack(spacing: 7) { + Text(ip).font(.system(size: 11)).foregroundColor(.secondary) + Button { + NSPasteboard.general.clearContents() + NSPasteboard.general.setString(ip, forType: .string) + } label: { + VPNIconView(icon: .copy) + } + .buttonStyle(.plain) + .keyboardShortcut("c", modifiers: [.command]) + .accessibilityLabel("Копировать IP") + .help("Копировать IP") + } + .padding(.top, 4) } - if remainingSec > 0 { - Text("Сессия: \(hours)ч \(mins)м") - .foregroundColor(.secondary) - } - Divider() - Button("Копировать IP") { - NSPasteboard.general.clearContents() - NSPasteboard.general.setString(ip, forType: .string) - } - .keyboardShortcut("c", modifiers: [.command]) - .disabled(ip.isEmpty) - - Button("Отключить") { - vpnManager.disconnect() - } - .keyboardShortcut("d") + if !vpnManager.tunnelHealthy { warning("Проблема соединения: VPN не отвечает") } + case .disconnected: + Text(vpnManager.connectionCheckMessage ?? "Готов к подключению") + .font(.system(size: 11)).foregroundColor(.secondary) + .fixedSize(horizontal: false, vertical: true) + case .disconnecting: + Text("Завершаем VPN и восстанавливаем DNS…").foregroundColor(.secondary) + case .unlocking: + Text("Подтвердите вход в Bitwarden").foregroundColor(.secondary) + case .connecting: + Text("Ожидаем VPN-соединение").foregroundColor(.secondary) + case .reconnecting(let attempt): + Text("Попытка \(attempt)").foregroundColor(.secondary) + case .error(let message): + warning(message) + if let checkMessage = vpnManager.connectionCheckMessage { warning(checkMessage) } } } - private func reconnectingMenu(attempt: Int) -> some View { - Group { - Label("Переподключение (\(attempt)/3)...", systemImage: "arrow.clockwise") - .disabled(true) - Divider() - Button("Отменить") { - vpnManager.disconnect() + @ViewBuilder private var connectionActions: some View { + if vpnManager.canRetryDisconnect { + Button { vpnManager.disconnect() } label: { iconLabel("Повторить отключение", icon: .disconnect).frame(maxWidth: .infinity) } + .buttonStyle(.bordered) + .controlSize(.small) + } else { + switch vpnManager.state { + case .disconnected, .error: + Button { vpnManager.connect() } label: { iconLabel("Подключить", icon: .connect).frame(maxWidth: .infinity) } + .buttonStyle(.bordered) + .controlSize(.small) + .disabled(!vpnManager.canConnect) + case .connected: + Button { vpnManager.disconnect() } label: { iconLabel("Отключить", icon: .disconnect).frame(maxWidth: .infinity) } + .buttonStyle(.bordered) + .controlSize(.small) + .keyboardShortcut("d") + case .disconnecting: + Button {} label: { iconLabel("Отключение…", icon: .disconnect).frame(maxWidth: .infinity) } + .buttonStyle(.bordered) + .controlSize(.small) + .disabled(true) + case .unlocking, .connecting, .reconnecting: + Button { vpnManager.disconnect() } label: { iconLabel("Отменить", icon: .cancel).frame(maxWidth: .infinity) } + .buttonStyle(.bordered) + .controlSize(.small) } } } - private func errorMenu(message: String) -> some View { - Group { - Label("Ошибка", systemImage: "exclamationmark.triangle") - .disabled(true) - Text(message) - .foregroundColor(.secondary) - .lineLimit(3) - Divider() - Button("Подключить заново") { - vpnManager.connect() + private var separator: some View { Divider().padding(.vertical, 7) } + + private func menuButton(_ title: String, image: VPNIcon, action: @escaping () -> Void) -> some View { + Button(action: action) { + HStack(spacing: 9) { + VPNIconView(icon: image).foregroundColor(.secondary) + Text(title) + Spacer(minLength: 0) } + .padding(.vertical, 6) + .contentShape(Rectangle()) + } + .buttonStyle(.plain) + } + + private func iconLabel(_ title: String, icon: VPNIcon) -> some View { + Label { Text(title) } icon: { VPNIconView(icon: icon) } + } + + private func warning(_ message: String) -> some View { + iconLabel(message, icon: .setup) + .font(.system(size: 11)) + .foregroundColor(.secondary) + .fixedSize(horizontal: false, vertical: true) + .padding(.top, 6) + } + + private var additionalError: String? { + if case .error(let message) = vpnManager.state, message == vpnManager.lastError { return nil } + return vpnManager.lastError + } + + private var moduleWarnings: [String] { + if vpnManager.isCheckingConnection { return [] } + guard let modules = vpnManager.moduleStatus else { return ["Не удалось проверить установку. Обновите статус."] } + var warnings: [String] = [] + if !modules.core.openconnect || !modules.core.openconnect_lite || !modules.core.openconnect_lite_config { + warnings.append("Установка не завершена. Запустите установщик Lemana VPN.") + } + if modules.bitwarden.enabled && !modules.bitwarden.installed { warnings.append("Bitwarden не установлен.") } + if modules.touchid.enabled && !modules.touchid.installed { warnings.append("Touch ID не настроен.") } + if !modules.dns_cleanup.installed { warnings.append("Очистка DNS не настроена. Обновите установку.") } + if !modules.patches.active { warnings.append("Подготовка SSO завершится при следующем подключении.") } + if modules.app?.installed == false { warnings.append("Приложение не установлено. Запустите установщик Lemana VPN.") } + return warnings + } + + private var statusTitle: String { + if vpnManager.state == .disconnecting { return "Отключение" } + if vpnManager.isCheckingConnection { return "Проверка" } + if vpnManager.connectionCheckFailed { return "Нужна проверка" } + if vpnManager.isExternallyActive { return "VPN ещё запущен" } + switch vpnManager.state { + case .disconnected: return "Отключён" + case .disconnecting: return "Отключение" + case .unlocking: return "Ожидаем вход" + case .connecting: return "Подключение" + case .connected: + if !vpnManager.tunnelHealthy { return "Проблема сети" } + return vpnManager.sessionTiming.remaining(at: Date()) == 0 ? "Срок истёк" : "Подключён" + case .reconnecting: return "Переподключение" + case .error: return "Ошибка" + } + } + + private var statusColor: Color { + if vpnManager.connectionCheckFailed { return .orange } + switch vpnManager.state { + case .connected: + return vpnManager.tunnelHealthy ? Color(nsColor: vpnManager.sessionTiming.urgency(at: Date()).color) : .red + case .error: return .red + default: return .secondary } } } diff --git a/app/Sources/LemanaVPN/SessionTiming.swift b/app/Sources/LemanaVPN/SessionTiming.swift new file mode 100644 index 0000000..8d9dda9 --- /dev/null +++ b/app/Sources/LemanaVPN/SessionTiming.swift @@ -0,0 +1,71 @@ +import Foundation + +enum VPNIndicatorStyle: String, CaseIterable, Identifiable { + case shield, ring, clock, time + + var id: String { rawValue } + var title: String { + switch self { + case .shield: return "Щит" + case .ring: return "Кольцо" + case .clock: return "Часы" + case .time: return "Время" + } + } +} + +struct SessionTiming { + enum Urgency { case normal, warning, critical, unknown } + + private(set) var startedAt: Date? + private(set) var expiresAt: Date? + + private var duration: TimeInterval? { + guard let start = startedAt, let end = expiresAt, end > start else { return nil } + return end.timeIntervalSince(start) + } + + mutating func observe(startedAt: String?, expires: String?, now: Date = Date()) { + let formatter = ISO8601DateFormatter() + if let start = startedAt.flatMap({ formatter.date(from: $0) }) { + // The CLI timestamp is authoritative, including after a legacy fallback. + self.startedAt = start + } else if self.startedAt == nil { + self.startedAt = now + } + if let expires = expires { + expiresAt = formatter.date(from: expires) + } + } + + func remaining(at now: Date) -> TimeInterval? { + guard duration != nil, let end = expiresAt else { return nil } + return max(0, end.timeIntervalSince(now)) + } + + func progress(at now: Date) -> Double? { + guard let duration = duration, let start = startedAt else { return nil } + return min(1, max(0, now.timeIntervalSince(start) / duration)) + } + + func urgency(at now: Date) -> Urgency { + guard let remaining = remaining(at: now) else { return .unknown } + if remaining <= 15 * 60 { return .critical } + if remaining <= 60 * 60 { return .warning } + return .normal + } + + func compactRemaining(at now: Date) -> String? { + guard let seconds = remaining(at: now) else { return nil } + let minutes = Int(ceil(seconds / 60)) + return String(format: "%d:%02d", minutes / 60, minutes % 60) + } + + func remainingLabel(at now: Date) -> String { + guard let seconds = remaining(at: now) else { return "Срок сессии неизвестен" } + if seconds <= 0 { return "Время сессии истекло" } + let minutes = Int(ceil(seconds / 60)) + if minutes < 60 { return "Осталось \(minutes) мин" } + return "Осталось \(minutes / 60) ч \(minutes % 60) мин" + } +} diff --git a/app/Sources/LemanaVPN/VPNIcons.swift b/app/Sources/LemanaVPN/VPNIcons.swift new file mode 100644 index 0000000..870a6f5 --- /dev/null +++ b/app/Sources/LemanaVPN/VPNIcons.swift @@ -0,0 +1,215 @@ +import AppKit + +enum VPNIcon: CaseIterable { + case off, connecting, unlock, connected, reconnect, network, error, setup, unknown, noTime, expired, clock + case connect, disconnect, cancel, importKey, password, copy, logs, refresh, quit, manual, auto, local, vault + + var isAction: Bool { + switch self { + case .connect, .disconnect, .cancel, .importKey, .password, .copy, .logs, .refresh, .quit, .manual, .auto, .local, .vault: return true + default: return false + } + } +} + +enum VPNIcons { + // Geometry and palettes from the approved artifacts/icon-family-v1/draw_icons.py. + static let shield: CGPath = { + let p = CGMutablePath() + p.move(to: CGPoint(x: 12, y: 2)) + p.addCurve(to: CGPoint(x: 20, y: 5), control1: CGPoint(x: 14.6, y: 3.7), control2: CGPoint(x: 17.3, y: 4.7)) + p.addLine(to: CGPoint(x: 20, y: 11.2)) + p.addCurve(to: CGPoint(x: 12, y: 22), control1: CGPoint(x: 20, y: 16.1), control2: CGPoint(x: 16.7, y: 19.6)) + p.addCurve(to: CGPoint(x: 4, y: 11.2), control1: CGPoint(x: 7.3, y: 19.6), control2: CGPoint(x: 4, y: 16.1)) + p.addLine(to: CGPoint(x: 4, y: 5)) + p.addCurve(to: CGPoint(x: 12, y: 2), control1: CGPoint(x: 6.7, y: 4.7), control2: CGPoint(x: 9.4, y: 3.7)) + p.closeSubpath() + return p + }() + + struct Palette { + let ink, muted, green, amber, red: NSColor + + init(dark: Bool) { + func color(_ hex: UInt32) -> NSColor { + NSColor(srgbRed: CGFloat((hex >> 16) & 255) / 255, green: CGFloat((hex >> 8) & 255) / 255, blue: CGFloat(hex & 255) / 255, alpha: 1) + } + ink = color(dark ? 0xE5EAF0 : 0x27333E) + muted = color(dark ? 0xACB7C3 : 0x657381) + green = color(dark ? 0x78CAA2 : 0x278055) + amber = color(dark ? 0xF0BB68 : 0xA56A13) + red = color(dark ? 0xF58C95 : 0xBE4149) + } + + func color(_ urgency: SessionTiming.Urgency) -> NSColor { + switch urgency { + case .normal: return green + case .warning: return amber + case .critical: return red + case .unknown: return muted + } + } + } + + static func image(_ icon: VPNIcon, dark: Bool) -> NSImage { + let result = image { draw(icon, in: $0, dark: dark) } + result.isTemplate = icon.isAction || [.off, .connecting, .unlock, .reconnect, .unknown, .noTime].contains(icon) + return result + } + + static func sessionImage(style: VPNIndicatorStyle, progress: Double?, urgency: SessionTiming.Urgency, dark: Bool) -> NSImage { + image { drawSession(style: style, progress: progress, urgency: urgency, in: $0, dark: dark) } + } + + private static func image(_ draw: @escaping (CGContext) -> Void) -> NSImage { + NSImage(size: NSSize(width: 16, height: 16), flipped: true) { _ in + guard let context = NSGraphicsContext.current?.cgContext else { return false } + context.saveGState() + context.scaleBy(x: 16 / 24, y: 16 / 24) + draw(context) + context.restoreGState() + return true + } + } + + static func draw(_ icon: VPNIcon, in context: CGContext, dark: Bool) { + let palette = Palette(dark: dark) + let color: NSColor + switch icon { + case .connected, .clock: color = palette.green + case .network, .setup: color = palette.amber + case .error, .expired: color = palette.red + default: color = palette.ink + } + context.saveGState() + if !icon.isAction { stroke(shield, in: context, color: palette.ink) } + stroke(mark(icon), in: context, color: color) + context.setFillColor(color.cgColor) + if icon == .connecting { + for x in [9.0, 12.0, 15.0] { context.fillEllipse(in: CGRect(x: x - 0.7, y: 11.3, width: 1.4, height: 1.4)) } + } else if icon == .setup || icon == .unknown { + context.fillEllipse(in: CGRect(x: 11.35, y: (icon == .setup ? 15.5 : 15.9) - 0.65, width: 1.3, height: 1.3)) + } + context.restoreGState() + } + + static func drawSession(style: VPNIndicatorStyle, progress: Double?, urgency: SessionTiming.Urgency, in context: CGContext, dark: Bool) { + guard let value = progress, value.isFinite else { + draw(.noTime, in: context, dark: dark) + return + } + let progress = min(1, max(0, value)) + let remaining = 1 - progress + let palette = Palette(dark: dark) + let accent = palette.color(urgency) + if style == .time { + stroke(shield, in: context, color: palette.ink) + stroke(mark(progress == 1 ? .expired : .connected), in: context, color: accent) + return + } + if style == .clock { + stroke(shield, in: context, color: palette.ink) + if progress == 1 { + stroke(mark(.expired), in: context, color: accent) + } else { + let hand = CGMutablePath() + hand.move(to: CGPoint(x: 12, y: 7.5)) + hand.addLine(to: CGPoint(x: 12, y: 12)) + let angle = progress * .pi * 2 + hand.addLine(to: CGPoint(x: 12 + sin(angle) * 4.5, y: 12 - cos(angle) * 4.5)) + stroke(hand, in: context, color: accent) + } + return + } + let ring = style == .ring + let shape = ring ? CGPath(ellipseIn: CGRect(x: 3, y: 3, width: 18, height: 18), transform: nil) : shield + let height: CGFloat = ring ? 18 : 20 + let bottom: CGFloat = ring ? 21 : 22 + context.saveGState() + context.addPath(shape) + context.clip() + context.setFillColor(palette.muted.withAlphaComponent(0.30).cgColor) + context.fill(CGRect(x: 0, y: 0, width: 24, height: 24)) + context.setFillColor(accent.withAlphaComponent(0.80).cgColor) + context.fill(CGRect(x: 0, y: bottom - height * remaining, width: 24, height: height * remaining)) + context.restoreGState() + stroke(shape, in: context, color: palette.muted.withAlphaComponent(ring ? 0.65 : 0.68)) + if remaining > 0 { + context.saveGState() + context.setLineCap(.butt) + context.setLineWidth(1.75) + context.setLineJoin(.round) + context.setStrokeColor(accent.cgColor) + if ring { + context.addArc(center: CGPoint(x: 12, y: 12), radius: 9, startAngle: -.pi / 2, endAngle: -.pi / 2 + remaining * .pi * 2, clockwise: false) + } else { + context.setLineDash(phase: 0, lengths: [remaining * 58.04152102, 58.04152102]) + context.addPath(shape) + } + context.strokePath() + context.restoreGState() + } + if progress == 1 { stroke(mark(.expired), in: context, color: palette.ink) } + } + + private static func stroke(_ path: CGPath, in context: CGContext, color: NSColor) { + context.setLineWidth(1.75) + context.setLineCap(.round) + context.setLineJoin(.round) + context.setStrokeColor(color.cgColor) + context.addPath(path) + context.strokePath() + } + + private static func mark(_ icon: VPNIcon) -> CGPath { + let p = CGMutablePath() + func m(_ x: CGFloat, _ y: CGFloat) { p.move(to: CGPoint(x: x, y: y)) } + func l(_ x: CGFloat, _ y: CGFloat) { p.addLine(to: CGPoint(x: x, y: y)) } + func c(_ x1: CGFloat, _ y1: CGFloat, _ x2: CGFloat, _ y2: CGFloat, _ x: CGFloat, _ y: CGFloat) { + p.addCurve(to: CGPoint(x: x, y: y), control1: CGPoint(x: x1, y: y1), control2: CGPoint(x: x2, y: y2)) + } + func circle(_ x: CGFloat, _ y: CGFloat, _ r: CGFloat) { p.addEllipse(in: CGRect(x: x - r, y: y - r, width: 2 * r, height: 2 * r)) } + func rect(_ x: CGFloat, _ y: CGFloat, _ w: CGFloat, _ h: CGFloat, _ r: CGFloat) { + p.addRoundedRect(in: CGRect(x: x, y: y, width: w, height: h), cornerWidth: r, cornerHeight: r) + } + switch icon { + case .off: m(8.7, 8.7); l(15.3, 15.3) + case .connecting: break + case .unlock: circle(10, 10.5, 1.8); m(11.4, 11.9); l(15.4, 15.9); m(13.5, 14); l(15, 12.5) + case .connected: m(7.8, 11.8); l(10.8, 14.7); l(16.2, 9.3) + case .reconnect: + p.addArc(center: CGPoint(x: 12.107508, y: 12.15), radius: 4, startAngle: -0.509224, endAngle: 0.509224, clockwise: true) + m(15.6, 7.3); l(15.6, 10.2); l(12.7, 10.2) + case .network: + m(10, 10); l(9, 10); p.addArc(center: CGPoint(x: 9, y: 12), radius: 2, startAngle: -.pi / 2, endAngle: -.pi * 1.5, clockwise: true); l(10, 14) + m(14, 10); l(15, 10); p.addArc(center: CGPoint(x: 15, y: 12), radius: 2, startAngle: -.pi / 2, endAngle: .pi / 2, clockwise: false); l(14, 14) + case .error: m(9, 9); l(15, 15); m(15, 9); l(9, 15) + case .setup: m(12, 7.8); l(12, 12.3) + case .unknown: m(9.7, 9.2); c(9.8, 6.7, 14.6, 6.7, 14.6, 9.4); c(14.6, 11.3, 12, 11.3, 12, 13) + case .expired: m(9, 8); l(15, 8); m(9, 16); l(15, 16); m(9.7, 8); c(9.7, 10.3, 14.3, 13.7, 14.3, 16); m(14.3, 8); c(14.3, 10.3, 9.7, 13.7, 9.7, 16) + case .noTime: m(9, 12); l(15, 12) + case .clock: m(12, 7.5); l(12, 12); l(15, 13.7) + case .connect: + m(8, 3); l(8, 8); m(16, 3); l(16, 8); m(6, 8); l(18, 8); l(18, 11); c(18, 14.3, 15.3, 17, 12, 17); c(8.7, 17, 6, 14.3, 6, 11); p.closeSubpath(); m(12, 17); l(12, 21) + case .disconnect: + m(8, 2.5); l(8, 6); m(16, 2.5); l(16, 6); m(6, 6); l(18, 6); l(18, 8); c(18, 10.2, 15.3, 11.5, 12, 11.5); c(8.7, 11.5, 6, 10.2, 6, 8); p.closeSubpath() + m(7.5, 15.5); p.addQuadCurve(to: CGPoint(x: 16.5, y: 15.5), control: CGPoint(x: 12, y: 19.5)); m(12, 17.5); l(12, 21.5) + case .cancel: m(6, 6); l(18, 18); m(18, 6); l(6, 18) + case .importKey: m(5, 13); l(5, 20); l(19, 20); l(19, 13); m(12, 3); l(12, 15); m(8, 11); l(12, 15); l(16, 11) + case .password: circle(8, 8, 4); m(11, 11); l(20, 20); m(15, 15); l(17, 13); m(18, 18); l(20, 16) + case .copy: m(9, 4); l(19, 4); l(19, 15); m(5, 8); l(15, 8); l(15, 21); l(5, 21); p.closeSubpath() + case .logs: m(6, 3); l(14, 3); l(19, 8); l(19, 21); l(6, 21); p.closeSubpath(); m(14, 3); l(14, 8); l(19, 8); m(9, 12); l(16, 12); m(9, 16); l(16, 16) + case .refresh: + p.addArc(center: CGPoint(x: 12.174321, y: 11.291312), radius: 7.2, startAngle: -0.323870, endAngle: -2.413483, clockwise: true) + l(4, 9); m(4, 4); l(4, 9); l(9, 9) + m(5, 15); p.addArc(center: CGPoint(x: 11.825679, y: 12.708688), radius: 7.2, startAngle: 2.817723, endAngle: 0.728110, clockwise: true) + l(20, 15); m(20, 20); l(20, 15); l(15, 15) + case .quit: m(11, 3); l(4, 3); l(4, 21); l(11, 21); m(10, 12); l(21, 12); m(17, 8); l(21, 12); l(17, 16) + case .manual: rect(3, 6, 18, 12, 2); m(6.5, 10); l(7, 10); m(11.5, 10); l(12, 10); m(16.5, 10); l(17, 10); m(7, 14); l(17, 14) + case .auto: m(13, 3); l(6, 13); l(11, 13); l(10, 21); l(18, 10); l(13, 10); p.closeSubpath() + case .local: rect(5, 4, 14, 12, 1.5); m(2.5, 19); l(21.5, 19); l(20, 21); l(4, 21); p.closeSubpath() + case .vault: rect(4.5, 3, 15, 18, 2.5); circle(12, 12, 3.8); m(12, 8.2); l(12, 10); m(15.8, 12); l(14, 12); m(12, 15.8); l(12, 14); m(8.2, 12); l(10, 12) + } + return p + } +} diff --git a/app/Sources/LemanaVPN/VPNManager.swift b/app/Sources/LemanaVPN/VPNManager.swift index ed5cd5d..858c058 100644 --- a/app/Sources/LemanaVPN/VPNManager.swift +++ b/app/Sources/LemanaVPN/VPNManager.swift @@ -5,16 +5,20 @@ struct VPNEvent: Decodable { let event: String var ip: String? var expires: String? + var started_at: String? + var attempt_id: String? var remaining_sec: Int? var attempt: Int? var delay: Int? var reason: String? var message: String? var source: String? + var mode: String? var profile: String? var auth_profile: String? var tier: Int? var modules: ModuleStatus? + var result: String? } struct VPNStatusResponse: Decodable { @@ -22,6 +26,26 @@ struct VPNStatusResponse: Decodable { } struct ModuleStatus: Decodable { + struct Auth: Decodable { + var mode: String + var source: String + var auto_source: String + var label: String + var detail: String + var ready: Bool + var setup_hint: String? + } + struct Logging: Decodable { + var max_bytes: Int + } + + struct Mode: Decodable { + var id: String + var label: String + var ready: Bool + var setup_hint: String? + } + struct Core: Decodable { var openconnect: Bool var openconnect_lite: Bool @@ -46,6 +70,7 @@ struct ModuleStatus: Decodable { var configured_mode: String var available_modes: [String] var setup_hint: String? + } struct Keychain: Decodable { @@ -55,6 +80,8 @@ struct ModuleStatus: Decodable { struct DnsCleanup: Decodable { var installed: Bool + var recovery_supported: Bool? + var stop_supported: Bool? } struct Patches: Decodable { @@ -68,6 +95,7 @@ struct ModuleStatus: Decodable { } var core: Core + var mode: Mode? var credentials: Credentials? var app_menu: AppMenu? var bitwarden: ToggleModule @@ -76,20 +104,26 @@ struct ModuleStatus: Decodable { var dns_cleanup: DnsCleanup var patches: Patches var app: AppModule? + var logging: Logging? + var auth: Auth? var hasWarnings: Bool { let coreReady = core.openconnect && core.openconnect_lite && core.openconnect_lite_config let bitwardenReady = !bitwarden.enabled || bitwarden.installed let touchReady = !touchid.enabled || touchid.installed - let profile = credentials?.auth_profile ?? "manual" + let modeId = mode?.id ?? credentials?.auth_profile ?? "manual-keychain" let keychainReady: Bool - switch profile { - case "manual": - keychainReady = true - case "saved-login": - keychainReady = keychain.password - default: - keychainReady = keychain.password && keychain.totp_seed + if let auth = auth { + keychainReady = auth.ready + } else { + switch modeId { + case "manual-keychain", "saved-login": + keychainReady = mode?.ready ?? keychain.password + case "keychain-auto", "bitwarden-auto", "auto", "saved-totp": + keychainReady = keychain.password && keychain.totp_seed + default: + keychainReady = false + } } let appReady = app?.installed ?? true @@ -106,31 +140,12 @@ struct ModuleStatus: Decodable { hasWarnings ? "exclamationmark.triangle" : "checkmark.circle" } - var summary: String { - let coreState = core.openconnect && core.openconnect_lite && core.openconnect_lite_config ? "✅ core" : "⚠️ core" - let credentialState = credentials.map { "🔐 \($0.auth_profile ?? "manual")/\($0.source)" } ?? "🔐 legacy" - let bwState = bitwarden.enabled ? (bitwarden.installed ? "✅ bw" : "⚠️ bw") : "⏭️ bw" - let touchState = touchid.enabled ? (touchid.installed ? "✅ touch" : "⚠️ touch") : "⏭️ touch" - let dnsState = dns_cleanup.installed ? "✅ dns" : "⚠️ dns" - let appState = app.map { $0.installed ? "✅ app" : "⚠️ app" } ?? "❔ app" - let autostartState = app.map { $0.autostart ? "✅ autostart" : "⏭️ autostart" } ?? "❔ autostart" - let patchState = patches.active ? "✅ patches" : "⚠️ patches" - let keychainReady: Bool - switch credentials?.auth_profile ?? "manual" { - case "manual": - keychainReady = true - case "saved-login": - keychainReady = keychain.password - default: - keychainReady = keychain.password && keychain.totp_seed - } - let keychainState = "\(keychainReady ? "✅" : "⚠️") kc \(keychain.password ? "pass" : "-")/\(keychain.totp_seed ? "totp" : "-")" - return [coreState, credentialState, bwState, touchState, dnsState, appState, autostartState, patchState, keychainState].joined(separator: " | ") - } + } enum VPNState: Equatable { case disconnected + case disconnecting case unlocking(tier: String) case connecting case connected(ip: String, expiresAt: Date?, remainingSec: Int) @@ -140,6 +155,7 @@ enum VPNState: Equatable { var label: String { switch self { case .disconnected: return "disconnected" + case .disconnecting: return "disconnecting" case .unlocking(let t): return "unlocking(\(t))" case .connecting: return "connecting" case .connected(let ip, _, let r): return "connected(ip=\(ip), remaining=\(r)s)" @@ -151,6 +167,9 @@ enum VPNState: Equatable { enum VPNLaunchMode: String, Identifiable { case configured = "configured" + case manualKeychain = "manual-keychain" + case bitwardenAuto = "bitwarden-auto" + // Hidden compatibility fallback for older CLI status responses. case auto = "auto" case savedLogin = "saved-login" case manual = "saved-totp" @@ -161,6 +180,8 @@ enum VPNLaunchMode: String, Identifiable { var cliArgument: String? { switch self { case .configured: return nil + case .manualKeychain: return "manual-keychain" + case .bitwardenAuto: return "bitwarden-auto" case .auto: return "--auto" case .savedLogin: return "--saved-login" case .manual: return "--manual" @@ -168,14 +189,22 @@ enum VPNLaunchMode: String, Identifiable { } } - var menuTitle: String { - switch self { - case .configured: return "Подключить" - case .auto: return "Подключить автоматически" - case .savedLogin: return "Подставить только логин и пароль" - case .manual: return "Подключить с сохранёнными данными" - case .manualFull: return "Подключить полностью вручную" + +} + +struct VPNLineBuffer { + private var pending = Data() + + mutating func append(_ data: Data) -> [String] { + pending.append(data) + var lines: [String] = [] + while let end = pending.firstIndex(of: 10) { + if let line = String(data: pending[..? + private var quitCompletion: ((Bool) -> Void)? + private let disconnectTimeout: TimeInterval + private var terminalError: String? + private var currentAttemptID: String? + private var healthCheckGeneration = 0 private var consecutiveHealthFailures: Int = 0 - private var currentLaunchMode: VPNLaunchMode = .configured + private var fileLog: BoundedLog + private var logWriteFailed = false private let healthCheckInterval: TimeInterval = 10 - private let maxAutoReconnectAttempts: Int = 3 - private let maxHealthFailuresBeforeKill: Int = 3 - private let autoReconnectDelay: TimeInterval = 5 + private let maxHealthFailuresBeforeRestart: Int = 3 - private let scriptPath: String = { - let home = FileManager.default.homeDirectoryForCurrentUser.path - return "\(home)/bin/vpn-lemanapro.sh" - }() + private let scriptPath: String - init() { - refreshStatus() + init(scriptPath: String? = nil, logURL: URL? = nil, disconnectTimeout: TimeInterval = 45) { + let home = FileManager.default.homeDirectoryForCurrentUser + self.scriptPath = scriptPath ?? home.appendingPathComponent("bin/vpn-lemanapro.sh").path + self.fileLog = BoundedLog(url: logURL ?? home.appendingPathComponent("Library/Logs/LemanaVPN.log")) + self.disconnectTimeout = disconnectTimeout + refreshConnectionStatus() } var isRunning: Bool { process?.isRunning ?? false } - var remainingTime: String { - guard let expires = sessionExpiresAt else { return "" } - let remaining = Int(expires.timeIntervalSinceNow) - guard remaining > 0 else { return "expired" } - let h = remaining / 3600 - let m = (remaining % 3600) / 60 - return String(format: "%d:%02d", h, m) + var canSetAuth: Bool { + guard canConfigureCredentials, moduleStatus?.auth != nil else { return false } + switch state { + case .connecting, .unlocking, .reconnecting, .disconnecting: return false + default: return true + } } - var statusBarTitle: String { - switch state { - case .connected: - return remainingTime - default: - return "" + var canConnect: Bool { + canConfigureCredentials && !isRunning && !userInitiatedDisconnect && moduleStatus != nil && moduleStatus?.auth?.ready != false + } + + var needsDisconnectBeforeQuit: Bool { + if case .reconnecting = state { return true } + return isRunning || sessionReady || userInitiatedDisconnect || state == .disconnecting + } + var canRetryDisconnect: Bool { userInitiatedDisconnect && disconnectDeadline == nil && !stopInFlight } + + var canConfigureCredentials: Bool { + connectionReady && !isCheckingConnection && !isExternallyActive && !isSavingAuth && state != .disconnecting + } + + func refreshConnectionStatus() { + guard !isCheckingConnection, !isSavingAuth, !stopInFlight else { return } + if isRunning { + refreshStatus() + return } + if case .reconnecting = state { + refreshStatus() + return + } + isCheckingConnection = true + let epoch = connectionCheckEpoch + connectionReady = false + connectionCheckFailed = false + isExternallyActive = false + connectionCheckMessage = "Проверяю подключение и DNS…" + refreshStatus { [weak self] succeeded in + guard let self = self else { return } + guard epoch == self.connectionCheckEpoch else { + self.isCheckingConnection = false + if !self.stopInFlight && !self.isRunning { self.refreshConnectionStatus() } + return + } + guard succeeded else { + self.finishConnectionCheck(error: "Не удалось проверить VPN. Обновите статус; если ошибка повторится, выполните sh install.sh.") + return + } + guard self.moduleStatus?.dns_cleanup.recovery_supported == true else { + self.finishConnectionCheck(error: "Для восстановления DNS обновите Lemana VPN: sh install.sh.") + return + } + guard self.moduleStatus?.dns_cleanup.stop_supported == true else { + self.finishConnectionCheck(error: "Для безопасного отключения обновите Lemana VPN: sh install.sh.") + return + } + self.recoverDNS() + } + } + + private func finishConnectionCheck(error message: String) { + if state == .disconnecting { state = .disconnected } + isCheckingConnection = false + connectionReady = false + connectionCheckFailed = true + connectionCheckMessage = message + log("[dns] \(message)") + if userInitiatedDisconnect || quitCompletion != nil { finishDisconnect(error: message) } + } + + private func recoverDNS() { + let epoch = connectionCheckEpoch + let proc = Process() + proc.executableURL = URL(fileURLWithPath: "/bin/bash") + proc.arguments = [scriptPath, "--repair-dns", "--json"] + proc.environment = processEnvironment() + proc.standardInput = FileHandle.nullDevice + proc.standardError = FileHandle.nullDevice + let pipe = Pipe() + proc.standardOutput = pipe + proc.terminationHandler = { [weak self] process in + let data = pipe.fileHandleForReading.readDataToEndOfFile() + let response = try? JSONDecoder().decode(VPNEvent.self, from: data) + Task { @MainActor in + guard let self = self else { return } + // A check started before Stop cannot complete the pending quit. + if self.stopInFlight || epoch != self.connectionCheckEpoch { + self.isCheckingConnection = false + if !self.stopInFlight && !self.isRunning { self.refreshConnectionStatus() } + return + } + guard response?.event == "dns_recovery", process.terminationStatus == 0, + let result = response?.result, ["restored", "unchanged", "no_snapshot", "active"].contains(result) else { + let detail = response?.event == "dns_recovery" && response?.result == "error" ? response?.message : nil + self.finishConnectionCheck(error: detail?.isEmpty == false ? detail! : "Не удалось восстановить DNS. Обновите статус; если ошибка повторится, выполните sh install.sh.") + return + } + self.isCheckingConnection = false + if self.state == .disconnecting { self.state = .disconnected } + self.isExternallyActive = result == "active" + self.connectionReady = result != "active" + self.connectionCheckMessage = result == "active" + ? "Процессы VPN ещё работают. DNS пока не восстановлены. Дождитесь завершения и обновите статус." + : (result == "restored" ? "Исходные DNS восстановлены." : nil) + self.log("[dns] recovery result: \(result)") + if self.userInitiatedDisconnect || self.quitCompletion != nil { + self.finishDisconnect(error: result == "active" ? "Процессы VPN ещё работают. Повторите отключение после их завершения." : nil) + } else if result != "active" { + self.sessionReady = false + self.sessionID = nil + } + } + } + do { + try proc.run() + } catch { + finishConnectionCheck(error: "Не удалось запустить восстановление DNS. Обновите Lemana VPN: sh install.sh.") + } + } + + var remainingTime: String { + sessionTiming.compactRemaining(at: Date()) ?? "" } var installModeLabel: String { @@ -243,6 +395,7 @@ class VPNManager: ObservableObject { } var installSetupHint: String? { + if let auth = moduleStatus?.auth { return auth.setup_hint } if let hint = moduleStatus?.app_menu?.setup_hint { return hint } @@ -252,33 +405,37 @@ class VPNManager: ObservableObject { return nil } - var availableLaunchModes: [VPNLaunchMode] { - guard let menu = moduleStatus?.app_menu else { - return [.configured] - } - let modes = menu.available_modes.compactMap(VPNLaunchMode.init(rawValue:)) - return modes.isEmpty ? [.configured] : modes - } - - func refreshStatus() { + func refreshStatus(completion: ((Bool) -> Void)? = nil) { + guard (!isSavingAuth && !isCheckingConnection) || completion != nil else { return } + statusGeneration += 1 + let generation = statusGeneration let proc = Process() proc.executableURL = URL(fileURLWithPath: "/bin/bash") - proc.arguments = ["-l", scriptPath, "--status", "--json"] + proc.arguments = [scriptPath, "--status", "--json"] proc.environment = processEnvironment() + proc.standardInput = FileHandle.nullDevice let pipe = Pipe() proc.standardOutput = pipe proc.standardError = FileHandle.nullDevice - proc.terminationHandler = { [weak self] _ in + proc.terminationHandler = { [weak self] process in let data = pipe.fileHandleForReading.readDataToEndOfFile() guard let self = self else { return } let text = String(data: data, encoding: .utf8) ?? "" let lastLine = text.split(separator: "\n").map(String.init).last ?? "" Task { @MainActor in + var succeeded = false + defer { completion?(succeeded) } + guard generation == self.statusGeneration else { return } + guard process.terminationStatus == 0 else { + self.moduleStatusSystemImage = "exclamationmark.triangle" + self.moduleStatus = nil + self.log("[modules] status exited with code \(process.terminationStatus)") + return + } guard !lastLine.isEmpty, let jsonData = lastLine.data(using: .utf8) else { - self.moduleSummary = "modules unavailable" self.moduleStatusSystemImage = "questionmark.circle" self.moduleStatus = nil self.log("[modules] status refresh returned no JSON output") @@ -289,7 +446,6 @@ class VPNManager: ObservableObject { do { response = try JSONDecoder().decode(VPNStatusResponse.self, from: jsonData) } catch { - self.moduleSummary = "modules unavailable" self.moduleStatusSystemImage = "exclamationmark.triangle" self.moduleStatus = nil let compact = text.replacingOccurrences(of: "\n", with: "\\n") @@ -299,45 +455,81 @@ class VPNManager: ObservableObject { } guard let modules = response.modules else { - self.moduleSummary = "modules unavailable: update CLI" self.moduleStatusSystemImage = "exclamationmark.triangle" self.moduleStatus = nil self.log("[modules] status has no modules field; reinstall CLI with install.sh") return } - self.moduleSummary = modules.summary self.moduleStatusSystemImage = modules.systemImage self.moduleStatus = modules + succeeded = true } } do { try proc.run() } catch { + moduleStatus = nil + moduleStatusSystemImage = "exclamationmark.triangle" log("[modules] status refresh failed: \(error.localizedDescription)") + completion?(false) + } + } + + func setAuth(_ choice: String) { + guard canSetAuth, ["manual", "auto", "keychain", "bitwarden"].contains(choice) else { return } + isSavingAuth = true + statusGeneration += 1 // Ignore refreshes started before the settings write. + lastError = nil + let proc = Process() + proc.executableURL = URL(fileURLWithPath: "/bin/bash") + proc.arguments = [scriptPath, "--set-auth=\(choice)"] + proc.environment = processEnvironment() + proc.standardOutput = FileHandle.nullDevice + proc.standardError = FileHandle.nullDevice + proc.terminationHandler = { [weak self] process in + Task { @MainActor in + guard let self = self else { return } + if process.terminationStatus != 0 { + self.isSavingAuth = false + self.lastError = "Не удалось сохранить способ входа. Проверьте установку Lemana VPN." + return + } + self.refreshStatus { succeeded in + self.isSavingAuth = false + if !succeeded { self.lastError = "Способ входа сохранён. Обновите статус, чтобы увидеть настройку." } + } + } + } + do { + try proc.run() + } catch { + isSavingAuth = false + lastError = "Не удалось запустить настройку способа входа. Обновите установку." } } func connect(mode: VPNLaunchMode = .configured) { - guard !isRunning else { - log("connect() called but process already running") + guard canConnect else { + log("connect() skipped until connection checks and settings are ready") return } - currentLaunchMode = mode log("-- VPN connect requested (\(mode.rawValue)) --") refreshStatus() state = .connecting + terminalError = nil lastError = nil - sessionExpiresAt = nil + sessionTiming = SessionTiming() + outputBuffer = VPNLineBuffer() currentIP = "" userInitiatedDisconnect = false - reconnectTimer?.invalidate() - reconnectTimer = nil + sessionID = UUID().uuidString.lowercased() + sessionReady = false let proc = Process() proc.executableURL = URL(fileURLWithPath: "/bin/bash") - var arguments = ["-l", scriptPath, "--json"] + var arguments = [scriptPath, "--json", "--session-id=\(sessionID!)"] if let cliArgument = mode.cliArgument { arguments.append(cliArgument) } @@ -354,18 +546,16 @@ class VPNManager: ObservableObject { self.outputPipe = stdoutPipe self.stderrPipe = errPipe - stdoutPipe.fileHandleForReading.readabilityHandler = { [weak self] handle in + stdoutPipe.fileHandleForReading.readabilityHandler = { [weak self, weak proc] handle in let data = handle.availableData guard !data.isEmpty else { handle.readabilityHandler = nil return } - if let text = String(data: data, encoding: .utf8) { - let lines = text.split(separator: "\n").map(String.init) - Task { @MainActor in - for jsonLine in lines { - self?.parseEvent(jsonLine) - } + Task { @MainActor in + guard let self = self, let proc = proc, self.process === proc else { return } + for jsonLine in self.outputBuffer.append(data) { + self.parseEvent(jsonLine) } } } @@ -388,6 +578,7 @@ class VPNManager: ObservableObject { proc.terminationHandler = { [weak self] proc in Task { @MainActor in + guard self?.process === proc else { return } self?.handleTermination(exitCode: proc.terminationStatus) } } @@ -402,30 +593,101 @@ class VPNManager: ObservableObject { } func disconnect() { - guard let proc = process, proc.isRunning else { - log("disconnect() called but no running process") - reconnectTimer?.invalidate() - reconnectTimer = nil - if case .reconnecting = state { state = .disconnected } - return - } + guard disconnectDeadline == nil, !stopInFlight else { return } userInitiatedDisconnect = true - log("-- VPN disconnect requested (SIGINT -> pid \(proc.processIdentifier)) --") - proc.interrupt() + connectionCheckEpoch += 1 + connectionReady = false + lastError = nil + state = .disconnecting + stopTimer() + stopHealthCheck() + log("-- VPN session stop requested --") + disconnectDeadline = Task { [weak self] in + guard let self = self else { return } + do { try await Task.sleep(nanoseconds: UInt64(self.disconnectTimeout * 1_000_000_000)) } + catch { return } + let pendingStop = self.stopProcess + self.stopProcess = nil + self.stopInFlight = false + if pendingStop?.isRunning == true { pendingStop?.terminate() } + self.finishDisconnect(error: "Отключение не завершилось. Приложение осталось открытым; повторите отключение.") + } + if sessionReady { stopSession() } + else if !isRunning { refreshConnectionStatus() } + // If launch is still registering, session_ready will perform the pending stop. + } + + private func stopSession() { + guard !stopInFlight, let sessionID = sessionID else { return } + stopInFlight = true + let proc = Process() + stopProcess = proc + proc.executableURL = URL(fileURLWithPath: "/bin/bash") + proc.arguments = [scriptPath, "--stop-session=\(sessionID)", "--json"] + proc.environment = processEnvironment() + proc.standardInput = FileHandle.nullDevice + proc.standardError = FileHandle.nullDevice + let pipe = Pipe() + proc.standardOutput = pipe + proc.terminationHandler = { [weak self] process in + let data = pipe.fileHandleForReading.readDataToEndOfFile() + let event = try? JSONDecoder().decode(VPNEvent.self, from: data) + Task { @MainActor in + guard let self = self, self.sessionID == sessionID, self.stopProcess === process else { return } + self.stopProcess = nil + self.stopInFlight = false + guard process.terminationStatus == 0, event?.event == "session_stop", event?.result == "stopping" else { + self.finishDisconnect(error: "Не удалось остановить нашу VPN-сессию. Проверьте установку: sh install.sh; затем повторите отключение.") + return + } + self.log("[disconnect] session stop acknowledged") + if !self.isRunning { self.refreshConnectionStatus() } + } + } + do { try proc.run() } + catch { + stopProcess = nil + stopInFlight = false + finishDisconnect(error: "Не удалось запустить остановку VPN. Обновите установку: sh install.sh.") + } + } + + private func finishDisconnect(error: String?) { + disconnectDeadline?.cancel() + disconnectDeadline = nil + if let error = error { + lastError = error + state = .error(message: error) + connectionReady = false + log("[disconnect] \(error)") + } else { + userInitiatedDisconnect = false + sessionReady = false + sessionID = nil + state = .disconnected + lastError = nil + } + let completion = quitCompletion + quitCompletion = nil + completion?(error == nil) } func configureLogin() { - openTerminalCommand(name: "configure-login", command: "\(shellQuote(scriptPath)) --configure-login") + guard canConfigureCredentials else { return } + openTerminalCommand(name: "configure-login", argument: "--configure-login", successMessage: "Логин и пароль обновлены.") } - func quit() { - log("-- App quit --") - userInitiatedDisconnect = true - reconnectTimer?.invalidate() - reconnectTimer = nil + func importYandexKey() { + guard canConfigureCredentials else { return } + openTerminalCommand(name: "import-yandex-key", argument: "--import-yandex-key", successMessage: "Код импортирован. Обновите статус в меню Lemana VPN.") + } + + func quit(completion: @escaping (Bool) -> Void) { + log("-- App quit requested --") + guard needsDisconnectBeforeQuit else { completion(true); return } + guard quitCompletion == nil else { return } + quitCompletion = completion disconnect() - stopTimer() - stopHealthCheck() } private func parseEvent(_ jsonString: String) { @@ -435,12 +697,6 @@ class VPNManager: ObservableObject { return } - if let modules = event.modules { - moduleSummary = modules.summary - moduleStatusSystemImage = modules.systemImage - moduleStatus = modules - } - log("[event] \(event.event)" + { var extras: [String] = [] if let ip = event.ip { extras.append("ip=\(ip)") } @@ -449,124 +705,159 @@ class VPNManager: ObservableObject { if let a = event.attempt { extras.append("attempt=\(a)") } if let m = event.message { extras.append("msg=\(m)") } if let r = event.reason { extras.append("reason=\(r)") } - if let p = event.auth_profile ?? event.profile { extras.append("profile=\(p)") } + if let p = event.mode ?? event.auth_profile ?? event.profile { extras.append("mode=\(p)") } return extras.isEmpty ? "" : " (\(extras.joined(separator: ", ")))" }()) - Task { @MainActor in - let prevState = state.label + let prevState = state.label - switch event.event { - case "modules": - return - case "credential_source": - if let message = event.message { - log(" \(message)") - } else if let source = event.source { - log(" Credential source: \(source)") - } - return - case "auth_profile": - if let message = event.message { - log(" \(message)") - } else if let profile = event.profile { - log(" Auth profile: \(profile)") - } - return - case "manual_sso", "auto_sso": - let profile = event.auth_profile ?? event.profile ?? "configured" - log(" SSO mode: \(profile)") - return - case "username_required", "username_saved": - if let message = event.message { - log(" \(message)") - } else if event.event == "username_required" { - log(" LDAP username is missing; configure it in Terminal") - } else { - log(" LDAP username saved") - } - return - case "bw_cached": - state = .unlocking(tier: "cached") - case "bw_touchid": - state = .unlocking(tier: "Touch ID") - case "bw_manual": - state = .unlocking(tier: "manual") - case "bw_synced": - log(" Credentials synced to Keychain") - return - case "keychain_ready": - log(" LDAP credentials are ready in macOS Keychain") - return - case "keychain_required": - log(" LDAP credentials are missing or incomplete") - return - case "log": - if let message = event.message { log(" \(message)") } - return - case "waiting": - if let message = event.message { log(" \(message)") } - return - case "connecting": - state = .connecting - case "connected": - currentIP = event.ip ?? "" - if let isoStr = event.expires { - sessionExpiresAt = ISO8601DateFormatter().date(from: isoStr) - } - let remaining = event.remaining_sec ?? Int(sessionExpiresAt?.timeIntervalSinceNow ?? 0) - state = .connected(ip: currentIP, expiresAt: sessionExpiresAt, remainingSec: remaining) - autoReconnectAttempts = 0 - startTimer() - detectVPNDNS() - case "session_info": - currentIP = event.ip ?? currentIP - if let isoStr = event.expires { - sessionExpiresAt = ISO8601DateFormatter().date(from: isoStr) - } - let remaining = event.remaining_sec ?? Int(sessionExpiresAt?.timeIntervalSinceNow ?? 0) - state = .connected(ip: currentIP, expiresAt: sessionExpiresAt, remainingSec: remaining) - case "disconnected": - state = .disconnected - stopTimer() - stopHealthCheck() - case "reconnecting": - state = .reconnecting(attempt: event.attempt ?? 1) - case "dns_cleanup": - log(" DNS cleanup in progress") - return - case "error": - lastError = event.message - state = .error(message: event.message ?? "Unknown error") - default: - log(" Unknown event type, ignoring") - return - } + if userInitiatedDisconnect || state == .disconnecting, + ["bw_cached", "bw_touchid", "bw_manual", "connecting", "connected", "session_info", "reconnecting", "disconnected", "error", "auth_rejected"].contains(event.event) { + return + } - if prevState != state.label { - log("[state] \(prevState) -> \(state.label)") + if terminalError != nil, ["connecting", "connected", "session_info", "reconnecting", "disconnected"].contains(event.event) { return } + + switch event.event { + case "session_ready": + sessionReady = true + if userInitiatedDisconnect { + if disconnectDeadline != nil { stopSession() } + else { disconnect() } } + return + case "modules": + return + case "credential_source": + if let message = event.message { + log(" \(message)") + } else if let source = event.source { + log(" Credential source: \(source)") + } + return + case "mode", "auth_profile": + if let message = event.message { + log(" \(message)") + } else if let mode = event.mode ?? event.profile { + log(" Mode: \(mode)") + } + return + case "manual_sso", "auto_sso": + let mode = event.mode ?? event.auth_profile ?? event.profile ?? "configured" + log(" SSO mode: \(mode)") + return + case "username_required", "username_saved": + if let message = event.message { + log(" \(message)") + } else if event.event == "username_required" { + log(" LDAP username is missing; configure it in Terminal") + } else { + log(" LDAP username saved") + } + return + case "bw_cached": + state = .unlocking(tier: "cached") + case "bw_touchid": + state = .unlocking(tier: "Touch ID") + case "bw_manual": + state = .unlocking(tier: "manual") + case "bw_synced": + log(" Credentials synced to Keychain") + return + case "keychain_ready": + log(" LDAP credentials are ready in macOS Keychain") + return + case "keychain_required": + log(" LDAP credentials are missing or incomplete") + return + case "log": + if let message = event.message { log(" \(message)") } + return + case "waiting": + if let message = event.message { log(" \(message)") } + return + case "connecting": + currentAttemptID = nil + stopHealthCheck() + sessionTiming = SessionTiming() + stopTimer() + state = .connecting + case "connected": + currentAttemptID = event.attempt_id + currentIP = event.ip ?? "" + sessionTiming.observe(startedAt: event.started_at, expires: event.expires) + let remaining = Int(sessionTiming.remaining(at: Date()) ?? Double(event.remaining_sec ?? 0)) + state = .connected(ip: currentIP, expiresAt: sessionTiming.expiresAt, remainingSec: remaining) + startTimer() + detectVPNDNS() + case "session_info": + guard case .connected = state else { return } + currentIP = event.ip ?? currentIP + sessionTiming.observe(startedAt: event.started_at, expires: event.expires) + let remaining = Int(sessionTiming.remaining(at: Date()) ?? Double(event.remaining_sec ?? 0)) + state = .connected(ip: currentIP, expiresAt: sessionTiming.expiresAt, remainingSec: remaining) + if timer == nil { startTimer() } + case "disconnected": + sessionTiming = SessionTiming() + state = .disconnected + stopTimer() + stopHealthCheck() + case "reconnecting": + stopHealthCheck() + sessionTiming = SessionTiming() + stopTimer() + state = .reconnecting(attempt: event.attempt ?? 1) + case "dns_cleanup": + state = .disconnecting + stopTimer() + stopHealthCheck() + log(" DNS cleanup in progress") + return + case "dns_recovery": + log(" DNS recovery result: \(event.result ?? "unknown")") + return + case "error", "auth_rejected": + stopHealthCheck() + sessionTiming = SessionTiming() + stopTimer() + terminalError = event.message ?? "Не удалось подключиться к VPN." + lastError = terminalError + state = .error(message: terminalError!) + default: + log(" Unknown event type, ignoring") + return + } + + if prevState != state.label { + log("[state] \(prevState) -> \(state.label)") } } - private func openTerminalCommand(name: String, command: String) { - let stateDir = FileManager.default.homeDirectoryForCurrentUser - .appendingPathComponent(".local/state/vpn-lemanapro") - let commandURL = stateDir.appendingPathComponent("\(name).command") - let script = """ + static func terminalScript(scriptPath: String, argument: String, successMessage: String) -> String { + func quote(_ value: String) -> String { + "'" + value.replacingOccurrences(of: "'", with: "'\\''") + "'" + } + return """ #!/bin/zsh - \(command) - status=$? + \(quote(scriptPath)) \(quote(argument)) + command_status=$? printf '\\n' - if [ "$status" -eq 0 ]; then - printf 'Логин и пароль обновлены.\\n' + if [ "$command_status" -eq 0 ]; then + printf '%s\\n' \(quote(successMessage)) else - printf 'Команда завершилась с ошибкой: %s\\n' "$status" + printf 'Команда завершилась с ошибкой: %s\\n' "$command_status" fi printf 'Нажмите Enter, чтобы закрыть окно...' read -r _ - exit "$status" + exit "$command_status" """ + } + + private func openTerminalCommand(name: String, argument: String, successMessage: String) { + let stateDir = FileManager.default.homeDirectoryForCurrentUser + .appendingPathComponent(".local/state/vpn-lemanapro") + let commandURL = stateDir.appendingPathComponent("\(name).command") + let script = Self.terminalScript(scriptPath: scriptPath, argument: argument, successMessage: successMessage) do { try FileManager.default.createDirectory(at: stateDir, withIntermediateDirectories: true) @@ -581,85 +872,55 @@ class VPNManager: ObservableObject { } catch { log("Credential setup launch failed: \(error.localizedDescription)") lastError = error.localizedDescription - state = .error(message: error.localizedDescription) + if !isRunning { state = .error(message: error.localizedDescription) } } } - private func shellQuote(_ value: String) -> String { - "'" + value.replacingOccurrences(of: "'", with: "'\\''") + "'" - } - private func handleTermination(exitCode: Int32) { log("-- Process terminated (exit=\(exitCode), userInitiated=\(userInitiatedDisconnect)) --") stopTimer() + sessionTiming = SessionTiming() stopHealthCheck() process = nil outputPipe = nil stderrPipe = nil - refreshStatus() let prevState = state.label if userInitiatedDisconnect { - state = .disconnected - userInitiatedDisconnect = false - autoReconnectAttempts = 0 - } else if currentLaunchMode != .auto { - log("Manual connection ended; auto-reconnect is disabled for manual mode") - state = .disconnected - autoReconnectAttempts = 0 - } else if [0, 2, 130, 143].contains(exitCode) { - scheduleAutoReconnect(reason: "session ended (exit \(exitCode))") + state = .disconnecting } else { - scheduleAutoReconnect(reason: "process crashed (exit \(exitCode))") + if terminalError == nil && ![0, 2, 130, 143].contains(exitCode) { + terminalError = exitCode == 77 + ? "Автоматический вход остановлен. Проверьте пароль и одноразовый код." + : "Подключение завершилось с ошибкой. Проверьте сеть и настройки входа." + } + lastError = terminalError + state = terminalError.map { .error(message: $0) } ?? .disconnected } if prevState != state.label { log("[state] \(prevState) -> \(state.label)") } - } - - private func scheduleAutoReconnect(reason: String) { - autoReconnectAttempts += 1 - if autoReconnectAttempts > maxAutoReconnectAttempts { - log("Auto-reconnect limit reached (\(maxAutoReconnectAttempts) attempts). Giving up.") - state = .error(message: "Не удалось переподключиться (\(autoReconnectAttempts - 1) попыток)") - autoReconnectAttempts = 0 - return - } - - log("Auto-reconnect #\(autoReconnectAttempts)/\(maxAutoReconnectAttempts) in \(Int(autoReconnectDelay))s (reason: \(reason))") - state = .reconnecting(attempt: autoReconnectAttempts) - - reconnectTimer?.invalidate() - reconnectTimer = Timer.scheduledTimer(withTimeInterval: autoReconnectDelay, repeats: false) { [weak self] _ in - Task { @MainActor in - guard let self = self else { return } - self.reconnectTimer = nil - guard case .reconnecting = self.state else { - self.log("Auto-reconnect cancelled (state changed)") - return - } - self.connect(mode: self.currentLaunchMode) - } - } + refreshConnectionStatus() } private func startTimer() { stopTimer() - timer = Timer.scheduledTimer(withTimeInterval: 60, repeats: true) { [weak self] _ in + timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] _ in Task { @MainActor in guard let self = self else { return } if case .connected = self.state { - let remaining = Int(self.sessionExpiresAt?.timeIntervalSinceNow ?? 0) + let remaining = Int(self.sessionTiming.remaining(at: Date()) ?? 0) self.state = .connected( ip: self.currentIP, - expiresAt: self.sessionExpiresAt, + expiresAt: self.sessionTiming.expiresAt, remainingSec: remaining ) } } } + timer?.tolerance = 0.2 } private func stopTimer() { @@ -668,6 +929,7 @@ class VPNManager: ObservableObject { } private func detectVPNDNS() { + let generation = healthCheckGeneration log("[health] Detecting VPN DNS via scutil --dns...") let proc = Process() proc.executableURL = URL(fileURLWithPath: "/usr/sbin/scutil") @@ -699,7 +961,7 @@ class VPNManager: ObservableObject { } Task { @MainActor in - guard let self = self else { return } + guard let self = self, self.healthCheckGeneration == generation, case .connected = self.state else { return } self.healthCheckTarget = dnsServer if let dns = dnsServer { self.log("[health] VPN DNS discovered: \(dns)") @@ -732,6 +994,7 @@ class VPNManager: ObservableObject { } private func stopHealthCheck() { + healthCheckGeneration += 1 if healthTimer != nil { log("[health] Stopped") } @@ -752,9 +1015,10 @@ class VPNManager: ObservableObject { proc.standardError = FileHandle.nullDevice let wasHealthy = tunnelHealthy + let generation = healthCheckGeneration proc.terminationHandler = { [weak self] p in Task { @MainActor in - guard let self = self, case .connected = self.state else { return } + guard let self = self, self.healthCheckGeneration == generation, case .connected = self.state else { return } let nowHealthy = p.terminationStatus == 0 if nowHealthy { @@ -767,15 +1031,12 @@ class VPNManager: ObservableObject { if wasHealthy { self.log("[health] Unreachable - ping \(target) (fail #\(self.consecutiveHealthFailures))") } else { - self.log("[health] Still unreachable (fail #\(self.consecutiveHealthFailures)/\(self.maxHealthFailuresBeforeKill))") + self.log("[health] Still unreachable (fail #\(self.consecutiveHealthFailures)/\(self.maxHealthFailuresBeforeRestart))") } - if self.consecutiveHealthFailures >= self.maxHealthFailuresBeforeKill { - self.log("[health] Tunnel dead after \(self.consecutiveHealthFailures) failures - killing process for reconnect") - self.stopHealthCheck() - if let proc = self.process, proc.isRunning { - proc.terminate() - } + if self.consecutiveHealthFailures >= self.maxHealthFailuresBeforeRestart { + self.log("[health] Tunnel unreachable; requesting an owned-engine restart") + self.restartSession() return } } @@ -794,8 +1055,41 @@ class VPNManager: ObservableObject { } } + private func restartSession() { + guard !userInitiatedDisconnect, sessionReady, let sessionID = sessionID, + let attemptID = currentAttemptID, !attemptID.isEmpty, + let connection = process, connection.isRunning else { return } + stopHealthCheck() + tunnelHealthy = false + let generation = healthCheckGeneration + let request = Process() + request.executableURL = URL(fileURLWithPath: "/bin/bash") + request.arguments = [scriptPath, "--restart-session=\(sessionID)", "--restart-attempt=\(attemptID)"] + request.environment = processEnvironment() + request.standardInput = FileHandle.nullDevice + request.standardOutput = FileHandle.nullDevice + request.standardError = FileHandle.nullDevice + request.terminationHandler = { [weak self] result in + Task { @MainActor in + guard let self = self, self.process === connection, self.sessionID == sessionID, + self.healthCheckGeneration == generation, !self.userInitiatedDisconnect else { return } + if result.terminationStatus != 0 { + self.lastError = "Не удалось безопасно перезапустить туннель. Отключите VPN и подключитесь заново." + self.log("[health] Owned-engine restart failed") + } + } + } + do { try request.run() } + catch { lastError = "Не удалось запустить переподключение. Отключите VPN и подключитесь заново." } + } + private func processEnvironment() -> [String: String] { var env = ProcessInfo.processInfo.environment + env.removeValue(forKey: "BASH_ENV") + // App actions always follow the saved configuration, not a parent shell's mode. + for key in ["LEMANA_VPN_MODE", "LEMANA_VPN_LOCAL_OTP", "LEMANA_VPN_AUTO_SOURCE", "LEMANA_VPN_AUTH_PROFILE", "LEMANA_VPN_CREDENTIAL_SOURCE", "LEMANA_VPN_USE_BITWARDEN"] { + env.removeValue(forKey: key) + } let home = FileManager.default.homeDirectoryForCurrentUser.path let extraPaths = [ "\(home)/bin", @@ -811,11 +1105,6 @@ class VPNManager: ObservableObject { return env } - private static let logURL: URL = { - FileManager.default.homeDirectoryForCurrentUser - .appendingPathComponent("Library/Logs/LemanaVPN.log") - }() - private static let tsFormatter: DateFormatter = { let f = DateFormatter() f.dateFormat = "yyyy-MM-dd HH:mm:ss" @@ -824,17 +1113,18 @@ class VPNManager: ObservableObject { }() func log(_ message: String) { + if let limit = moduleStatus?.logging?.max_bytes, (1...999_999_999).contains(limit) { + fileLog.maxBytes = limit + } let ts = Self.tsFormatter.string(from: Date()) let line = "[\(ts)] \(message)\n" - - let path = Self.logURL.path - if !FileManager.default.fileExists(atPath: path) { - FileManager.default.createFile(atPath: path, contents: nil) - } - if let handle = FileHandle(forWritingAtPath: path) { - handle.seekToEndOfFile() - handle.write(line.data(using: .utf8) ?? Data()) - handle.closeFile() + do { + try fileLog.append(line) + } catch { + if !logWriteFailed { + fputs("Cannot write Lemana VPN log: \(error.localizedDescription)\n", stderr) + logWriteFailed = true + } } } } diff --git a/artifacts/icon-family-v1/README.md b/artifacts/icon-family-v1/README.md new file mode 100644 index 0000000..69751ff --- /dev/null +++ b/artifacts/icon-family-v1/README.md @@ -0,0 +1,19 @@ +# Lemana VPN: единая семья значков + +Проект набора для согласования. Значки работающего приложения не заменены. + +34 варианта: состояния VPN, ход сессии, варианты времени, действия меню и источники входа. Один контур щита, сетка 24 единицы, основная линия 1,75 единицы; рабочий размер — 16 pt. Цвет всегда дополнен формой или подписью. + +- `svg/`: векторные версии для светлой и тёмной темы. +- `png/`: прозрачные превью высотой 96 px для просмотра в разных размерах. +- `icon-sheet-light.png` и `icon-sheet-dark.png`: весь набор крупно и в 16 pt. +- `lemana-vpn-icons-v1.zip`: SVG обеих тем и manifest. +- `draw_icons.py`: исходник геометрии и воспроизводимая сборка (Python 3 + rsvg-convert). + +Индикатор времени заполняется по часовой стрелке от верхушки щита. Внутри остаётся нейтральная подложка (14% цвета основного текста), поверх которой снизу вверх растёт заливка (60% текущего цвета). Высота заливки пропорциональна прошедшей доле сессии. Контур нейтральный, пройденная часть зелёная; последний час янтарный, последние 15 минут красные. На полном красном щите песочные часы контрастные, а не красные. Кольцо использует тот же принцип внутренней заливки. + +Образцы последних минут показаны для условной восьмичасовой сессии; в приложении доля должна вычисляться по реальным started_at/expires. Неизвестный срок имеет отдельную метку, а не нулевое заполнение. Обычные состояния, статические часы и действия меню не изменены. + +Bitwarden обозначен нейтральным значком хранилища, это не копия фирменного логотипа. + +Проверены структура SVG, доли заполнения и рендер контактных листов. Приложение/GUI не запускались. diff --git a/artifacts/icon-family-v1/draw_icons.py b/artifacts/icon-family-v1/draw_icons.py new file mode 100644 index 0000000..2dd4bb8 --- /dev/null +++ b/artifacts/icon-family-v1/draw_icons.py @@ -0,0 +1,168 @@ +"""Deterministic review assets for Lemana VPN; does not modify the application.""" +from pathlib import Path +import html +import json +import math +import subprocess +import zipfile + +ROOT = Path(__file__).resolve().parent +SHIELD = 'M12 2 C14.6 3.7 17.3 4.7 20 5 V11.2 C20 16.1 16.7 19.6 12 22 C7.3 19.6 4 16.1 4 11.2 V5 C6.7 4.7 9.4 3.7 12 2 Z' + +def curve_length(points): + previous=points[0]; length=0.0 + for i in range(1,513): + t=i/512; u=1-t + point=tuple(u**3*points[0][k]+3*u*u*t*points[1][k]+3*u*t*t*points[2][k]+t**3*points[3][k] for k in (0,1)) + length+=math.dist(previous,point); previous=point + return length + +SHIELD_LENGTH=2*(6.2+curve_length(((12,2),(14.6,3.7),(17.3,4.7),(20,5)))+curve_length(((20,11.2),(20,16.1),(16.7,19.6),(12,22)))) +PALETTES = { + 'light': dict(bg='#F6F7F8', surface='#ECEFF2', ink='#27333E', muted='#657381', line='#D6DDE3', green='#278055', amber='#A56A13', red='#BE4149'), + 'dark': dict(bg='#202429', surface='#2B3037', ink='#E5EAF0', muted='#ACB7C3', line='#444D57', green='#78CAA2', amber='#F0BB68', red='#F58C95'), +} + +def path(d, **attrs): + extra = ''.join(f' {key.replace("_", "-")}="{value}"' for key,value in attrs.items()) + return f'' + +def circle(x,y,r,**attrs): + extra = ''.join(f' {key.replace("_", "-")}="{value}"' for key,value in attrs.items()) + return f'' + + +def progress_interior(shape,progress,bottom,height,palette,accent): + body=shape(fill=palette['ink'],fill_opacity='.14',stroke='none') + if progress: + level=height*progress + top=bottom-level + # A nested viewport clips the fill level without shared SVG clip-path IDs. + body+=f'' + body+=shape(fill=accent,fill_opacity='.60',stroke='none')+'' + return body + +MARKS = { + 'off': path('M8.7 8.7 L15.3 15.3'), + 'connecting': ''.join(circle(x,12,.7,fill='currentColor',stroke='none') for x in (9,12,15)), + 'unlock': circle(10,10.5,1.8)+path('M11.4 11.9 L15.4 15.9 M13.5 14 L15 12.5'), + 'check': path('M7.8 11.8 L10.8 14.7 L16.2 9.3'), + 'reconnect': path('M15.6 10.2 A4 4 0 1 0 15.6 14.1 M15.6 7.3 V10.2 H12.7'), + 'network': path('M10 10 H9 A2 2 0 0 0 9 14 H10 M14 10 H15 A2 2 0 0 1 15 14 H14'), + 'error': path('M9 9 L15 15 M15 9 L9 15'), + 'setup': path('M12 7.8 V12.3')+circle(12,15.5,.65,fill='currentColor',stroke='none'), + 'unknown': path('M9.7 9.2 C9.8 6.7 14.6 6.7 14.6 9.4 C14.6 11.3 12 11.3 12 13')+circle(12,15.9,.65,fill='currentColor',stroke='none'), + 'expired': path('M9 8 H15 M9 16 H15 M9.7 8 C9.7 10.3 14.3 13.7 14.3 16 M14.3 8 C14.3 10.3 9.7 13.7 9.7 16'), + 'no-time': path('M9 12 H15'), + 'clock': path('M12 7.5 V12 L15 13.7'), +} +ACTIONS = { + 'connect': path('M8 3 V8 M16 3 V8 M6 8 H18 V11 C18 14.3 15.3 17 12 17 C8.7 17 6 14.3 6 11 Z M12 17 V21'), + 'disconnect': path('M8 2.5 V6 M16 2.5 V6 M6 6 H18 V8 C18 10.2 15.3 11.5 12 11.5 C8.7 11.5 6 10.2 6 8 Z M7.5 15.5 Q12 19.5 16.5 15.5 M12 17.5 V21.5'), + 'cancel': path('M6 6 L18 18 M18 6 L6 18'), + 'import': path('M5 13 V20 H19 V13 M12 3 V15 M8 11 L12 15 L16 11'), + 'password': circle(8,8,4)+path('M11 11 L20 20 M15 15 L17 13 M18 18 L20 16'), + 'copy': path('M9 4 H19 V15 M5 8 H15 V21 H5 Z'), + 'logs': path('M6 3 H14 L19 8 V21 H6 Z M14 3 V8 H19 M9 12 H16 M9 16 H16'), + 'refresh': path('M19 9 A7.2 7.2 0 0 0 6.8 6.5 L4 9 M4 4 V9 H9 M5 15 A7.2 7.2 0 0 0 17.2 17.5 L20 15 M20 20 V15 H15'), + 'quit': path('M11 3 H4 V21 H11 M10 12 H21 M17 8 L21 12 L17 16'), + 'manual': ''+path('M6.5 10 H7 M11.5 10 H12 M16.5 10 H17 M7 14 H17'), + 'auto': path('M13 3 L6 13 H11 L10 21 L18 10 H13 Z'), + 'local': ''+path('M2.5 19 H21.5 L20 21 H4 Z'), + 'vault': ''+circle(12,12,3.8)+path('M12 8.2 V10 M15.8 12 H14 M12 15.8 V14 M8.2 12 H10'), +} +ENTRIES=[] +def add(key,label,section,kind,mark='',tone='ink',progress=None): + ENTRIES.append(dict(key=key,label=label,section=section,kind=kind,mark=mark,tone=tone,progress=progress)) + +for args in [ + ('vpn-off','Отключён','off','ink'),('vpn-connecting','Подключение','connecting','ink'), + ('vpn-unlock','Ожидаем вход','unlock','ink'),('vpn-connected','Подключён','check','green'), + ('vpn-reconnect','Переподключение','reconnect','ink'),('vpn-network','Проблема сети','network','amber'), + ('vpn-error','Ошибка','error','red'),('vpn-setup','Нужна настройка','setup','amber'), + ('vpn-unknown','Статус неизвестен','unknown','ink')]: + add(args[0],args[1],'Состояния VPN','shield',args[2],args[3]) +for key,label,progress,tone in [ + ('time-start','Начало',0,'green'),('time-quarter','25% прошло',.25,'green'), + ('time-half','50% прошло',.5,'green'),('time-three-quarter','75% прошло',.75,'green'), + ('time-hour','Остался час',.875,'amber'),('time-quarter-hour','Осталось 15 мин',.96875,'red'), + ('time-expired','Срок истёк',1,'red')]: + add(key,label,'Время сессии','progress','expired' if progress==1 else '',tone,progress) +add('time-unknown','Срок неизвестен','Время сессии','shield','no-time') +add('format-shield','Щит с прогрессом','Форматы времени','progress','', 'green',.58) +add('format-clock','Щит-часы','Форматы времени','shield','clock','green') +add('format-time','Щит + время','Форматы времени','digital','check','green') +add('format-ring','Кольцо','Форматы времени','ring','', 'green',.58) +for key,label in [('connect','Подключить'),('disconnect','Отключить'),('cancel','Отменить'),('import','Импорт ключа'),('password','Логин и пароль'),('copy','Копировать IP'),('logs','Логи'),('refresh','Обновить статус'),('quit','Выход')]: + add('action-'+key,label,'Действия меню','action',key) +for key,label in [('manual','Вручную'),('auto','Автоматически'),('local','Ключ на Mac'),('vault','Bitwarden')]: + add('source-'+key,label,'Источники и режимы','action',key) + + +def content(entry,palette): + ink=palette['ink'];accent=palette[entry['tone']] + if entry['kind']=='action': return ACTIONS[entry['mark']] + if entry['kind']=='ring': + body=progress_interior(lambda **attrs:circle(12,12,9,**attrs),entry['progress'],21,18,palette,accent) + return body+circle(12,12,9,stroke=palette['muted'],stroke_opacity='.65')+circle(12,12,9,stroke=accent,stroke_dasharray=f'{entry["progress"]*math.tau*9:.5f} {math.tau*9:.5f}',transform='rotate(-90 12 12)',stroke_linecap='butt') + shape=path(SHIELD,stroke=ink) + if entry['kind']=='progress': + shape=progress_interior(lambda **attrs:path(SHIELD,**attrs),entry['progress'],22,20,palette,accent) + shape+=path(SHIELD,stroke=palette['muted'],stroke_opacity='.68') + if entry['progress']: + shape+=path(SHIELD,stroke=accent,stroke_dasharray=f'{entry["progress"]*SHIELD_LENGTH:.5f} {SHIELD_LENGTH:.5f}',stroke_linecap='butt') + if entry['mark']: + mark_color=ink if entry['kind']=='progress' else accent + shape+=f'{MARKS[entry["mark"]]}' + if entry['kind']=='digital': + shape+='2:18' + return shape + + +def svg(entry,theme): + p=PALETTES[theme];width=74 if entry['kind']=='digital' else 24 + return f'{html.escape(entry["label"])}'+content(entry,p)+'' + + +def text(x,y,value,size=14,color='#657381',weight=400): + return f'{html.escape(value)}' + + +def sheet(theme): + p=PALETTES[theme];width=1120;elements=[] + elements.append(text(42,53,'Lemana VPN',27,p['ink'],600)) + elements.append(text(42,82,'Единая семья значков',16,p['muted'])) + elements.append(text(824,53,'Щит / 16 pt',14,p['ink'],500)) + elements.append(text(824,78,'Контур 1,75 · сетка 24',12,p['muted'])) + y=130 + for section in dict.fromkeys(e['section'] for e in ENTRIES): + elements.append(text(42,y,section,16,p['ink'],500));y+=24 + subset=[e for e in ENTRIES if e['section']==section] + for index,e in enumerate(subset): + col=index%6;row=index//6;x=42+col*174;top=y+row*119 + logical_width=74 if e['kind']=='digital' else 24 + large_x=x+(160-logical_width*1.5)/2 + small_x=x+(160-logical_width*2/3)/2 + elements.append(f''+content(e,p)+'') + elements.append(f''+content(e,p)+'') + elements.append(text(x+7,top+91,e['label'],12,p['ink'])) + y+=((len(subset)+5)//6)*119+14 + elements.append(f'') + elements.append(text(42,y+10,'Увеличенный вид + 16 pt. Цвет дополнен формой и подписью.',12,p['muted'])) + elements.append(text(42,y+32,'Пример сессии: 8 ч. Контур и внутренняя заливка растут к её концу. Набор пока не установлен.',12,p['muted'])) + height=y+65 + return f''+''.join(elements)+'' + +for theme in PALETTES: + for e in ENTRIES: + source=ROOT/'svg'/f'{e["key"]}-{theme}.svg' + source.write_text(svg(e,theme)) + subprocess.run(['rsvg-convert',str(source),'-o',str(ROOT/'png'/f'{e["key"]}-{theme}.png'),'-h','96'],check=True) + source=ROOT/f'icon-sheet-{theme}.svg';source.write_text(sheet(theme)) + subprocess.run(['rsvg-convert',str(source),'-o',str(ROOT/f'icon-sheet-{theme}.png'),'-w','2240'],check=True) +(ROOT/'manifest.json').write_text(json.dumps(ENTRIES,ensure_ascii=False,indent=2)+'\n') +with zipfile.ZipFile(ROOT/'lemana-vpn-icons-v1.zip','w',zipfile.ZIP_DEFLATED) as archive: + for file in sorted((ROOT/'svg').glob('*.svg')): + archive.write(file,file.relative_to(ROOT)) + archive.write(ROOT/'manifest.json','manifest.json') +print(f'{len(ENTRIES)} icon entries, two themes, SVG assets and preview sheets created.') diff --git a/artifacts/icon-family-v1/icon-sheet-dark.png b/artifacts/icon-family-v1/icon-sheet-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..5088d1532416eded12b3b69468ac8ad51c3cd364 GIT binary patch literal 268079 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

&$;tb|-gk1NW_Hefjj%rhN-u?zCD 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

5Q;P)aVF|Jwu}G=l@*JGg!OyV>*3J;#**rR5D5 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 literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/vpn-network-dark.png b/artifacts/icon-family-v1/png/vpn-network-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..3d89eff9059a7648af1e5c40ec8fff4235f9ca14 GIT binary patch literal 3565 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 literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/vpn-network-light.png b/artifacts/icon-family-v1/png/vpn-network-light.png new file mode 100644 index 0000000000000000000000000000000000000000..315379e2e108c2c14856815550c3bcf569337acc GIT binary patch literal 3647 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 Ri9`SZ002ovPDHLkV1lJTA4UKG literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/vpn-off-dark.png b/artifacts/icon-family-v1/png/vpn-off-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..148f804ea96eb4207a9968aa3d9ae63b290ba04f GIT binary patch literal 3005 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 literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/vpn-off-light.png b/artifacts/icon-family-v1/png/vpn-off-light.png new file mode 100644 index 0000000000000000000000000000000000000000..eb86e118e30f74a4aaff3545134ef272dac1b2c6 GIT binary patch literal 3080 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 literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/vpn-reconnect-light.png b/artifacts/icon-family-v1/png/vpn-reconnect-light.png new file mode 100644 index 0000000000000000000000000000000000000000..3c850d8f1c5507facdd507fae4b71d88a7714043 GIT binary patch literal 3971 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 literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/vpn-setup-dark.png b/artifacts/icon-family-v1/png/vpn-setup-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..392fe1377319e937fb5354606c0c99ba4d85ed25 GIT binary patch literal 3018 zcmV;*3pMnKP)TP$;wsBtXjmg{Hv)%d(}l zE!oD7ZE5f62Ro1^+O>AItCgsJGydYU_nfQymv;BwJ@+h7rc9YKW&U3ww>w~!s5sZuiLwB`3h(;9&KHCT<1jasbNAzcql@S1R)6y1Kd%H~VLnk`ka- z9a;_+>jAW6vlF;aGOlk9)jU+-u34re1nB7>`hpN*Er7Nhn{+8sUfbAM`?iz)vV)=) zpl4v9i8RlTiEuGKJ>BGrB;X0scuhE5v&Vt%*+NkY5RZQx%81N0U|b2{kUZUu1Gq<# z%C8z5s}eSJ&sK^`fWE%ue5v4CfG$G*1AicU0e*lyyf#u>`;pDQEmIT%#1ccNGm8!) ze2W3Eld%X$GxKABa&J?p`tMH0%CSH0(49;Md{bg26JJKaaTZ*pz;qJ`MBtw@;J4u8 zEoN*?`}on;nwpe__IXoK0R{&Lt0yy_bC|FK;5Gmi7TidH9`ZuDAsC$74*+}Av9OOb zw=?)V0E7jflVIv1fycaTOE@k-fB(>N8HL)2sSUsx04nov_nc&TT}!C; zt!&0M9RsmF1t(t)6WFcuG6BZKaRDdJ- z`X$C|l5t~mV_<78$M?oliCTo$|EqR5jK)V!B_Y>&rT1D!;avB|F?JDI(aL~6MtT1mh%*fi-Q;;SPKHNQ5~ z#`L$CB?5U~y2nBEJb*uVd9pJY41S!KHw%1;C=K9A08gr_T9t-xIRh)eyad3ZR{gR> zz-${Q&fy2azy}0=227n(|?TPHyQq%k6$yq2vS@?P?Da%cltVWGR7w zFtL1Uw5vVnX5Xw(asp@yeG}QAe)(r?B}K^zK+L*}XhybTrQ`&V2D4BjTd`7d0({me z3*a(k0bHgmfXkExaGA0IE>jl3Wy%7$Oj!VzDGT5-WdU5qyZ}P51O51HU}0=b3qZ_M zdNwBVne|t45b3AaGn>wLvTzEbFV6>dpS2~b^0MdB@ z7^I)eNvJpLujF8=(=`?17eK7_>KYlXX8oCtPtg4Z8rkfEi4WI}&%$(Cy=eiY!rcaD z-OkwsG5ytw&9?Z!d_7xQC`MzG71IJV)z-!U=;h#4?NP@ZeJ<-?vSB+w8xOY7#%Y^# z^b8C%0hp^}o|spEXunyX=1)OH62J#~cAuO&#jH=W_!n>J0P(pDJj}quAU@Z>cteNN zaTU$8NY_ZTn}|%$11x365$H7rADzv{M2i6Y$%@~c;}aOT?{NT+I~gYnr|MdmE$wHs zv=kwk4SwqUWh*{Q1l`X@gu)2`@HTxLEpqxg;07P5YGh`UMplF-E!CZ{BtTOz@HPNd z&!-RR1QM}R{eri-+ARy#?;gXX0+>=M`Q)Hw)p)+ z`NYUZa#Qf;CrI^`F-hG0JG`49wLu z$=BxNUl%W3i2q4ZrvRjOp%bB`M_U8k!3Pw{S!U(Ala~O~wRHGzdUgU<$KxM|@`;fZ z=7VOOg4xnV(1<9?-&Onlm`L+bn`bMsS*F) z?l4}NUJIkr1w=-lJtu6*r;n+r?aa_y17a3f+*}{9e4)xla_i;ugw$36fCl+s?UMU# zt%TU4CeIX1FFl0@wQ zjIshQj;X`nwkw`fL=&kM0IxDQWD+D++ZE3?0a}9oU0^o6;4<^ZXd-!nT`}#ZH<3J% zfZrM&!@#Xg4b|`471P#DZQb2m>6<&U6U@gN92QNJcj5eoIem7<&X=BnfhHk6ufn+S z;6GCh{)NX9>E=e6#n#ls)>fJjnap{B;luG}FQ+?q4-HwVbn6J+$z(uC&oeL{{4o;B z`F0LI;6QF@I9&G*6Rw%%u#+n@Vw0+>x--l|(cj-c$CnmQ1DNI1$g3muRsXU(zGM4p zqiXVDV!FWS7zSSQ$ce8vHa42hr?G?S+s%q+XM2iApobzs|973}gJapz!}WoS33$=y z7y{17h|0h8^^G<-)ek*-hKFm@@NJ&`5h}ehHe7wFQ~hvsXL&R_Qb#_y9me<60Pr4p z$Wg4xE)WjO;qdnWUfC3^c{87w{ryA7WrTP%r?+$vJ_N*4J7>DH zQP4eNk^1WQ*rS~W=3G)Zjsj>~Zz6RaGn+55%^-Zq+OJt*UC(6udVR*N2&LzmL+#7u(cGqB&G;u%E$Qidp~wU}n*qNL@fgYXRiCY@H+6)qfWeVk^lez M07*qoM6N<$f*z-qBme*a literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/vpn-setup-light.png b/artifacts/icon-family-v1/png/vpn-setup-light.png new file mode 100644 index 0000000000000000000000000000000000000000..4b0b87ae782d591def128afa30f4dab11b7e3e9d GIT binary patch literal 3073 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 literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/vpn-unknown-light.png b/artifacts/icon-family-v1/png/vpn-unknown-light.png new file mode 100644 index 0000000000000000000000000000000000000000..1038690cf45cb47de05586c8ad9975107f17bcbd GIT binary patch literal 3654 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 YKP2$W*roUejsO4v07*qoM6N<$f=ntc{Qv*} literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/vpn-unlock-dark.png b/artifacts/icon-family-v1/png/vpn-unlock-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..06418c24c4bda1e2ec7b614c9f0f704b211d9d4e GIT binary patch literal 3519 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Отменить \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/action-cancel-light.svg b/artifacts/icon-family-v1/svg/action-cancel-light.svg new file mode 100644 index 0000000..4ed3fa1 --- /dev/null +++ b/artifacts/icon-family-v1/svg/action-cancel-light.svg @@ -0,0 +1 @@ +Отменить \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/action-connect-dark.svg b/artifacts/icon-family-v1/svg/action-connect-dark.svg new file mode 100644 index 0000000..e194dd2 --- /dev/null +++ b/artifacts/icon-family-v1/svg/action-connect-dark.svg @@ -0,0 +1 @@ +Подключить \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/action-connect-light.svg b/artifacts/icon-family-v1/svg/action-connect-light.svg new file mode 100644 index 0000000..a5e1c3f --- /dev/null +++ b/artifacts/icon-family-v1/svg/action-connect-light.svg @@ -0,0 +1 @@ +Подключить \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/action-copy-dark.svg b/artifacts/icon-family-v1/svg/action-copy-dark.svg new file mode 100644 index 0000000..ffd19d3 --- /dev/null +++ b/artifacts/icon-family-v1/svg/action-copy-dark.svg @@ -0,0 +1 @@ +Копировать IP \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/action-copy-light.svg b/artifacts/icon-family-v1/svg/action-copy-light.svg new file mode 100644 index 0000000..450d978 --- /dev/null +++ b/artifacts/icon-family-v1/svg/action-copy-light.svg @@ -0,0 +1 @@ +Копировать IP \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/action-disconnect-dark.svg b/artifacts/icon-family-v1/svg/action-disconnect-dark.svg new file mode 100644 index 0000000..4c094a8 --- /dev/null +++ b/artifacts/icon-family-v1/svg/action-disconnect-dark.svg @@ -0,0 +1 @@ +Отключить \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/action-disconnect-light.svg b/artifacts/icon-family-v1/svg/action-disconnect-light.svg new file mode 100644 index 0000000..4a2486e --- /dev/null +++ b/artifacts/icon-family-v1/svg/action-disconnect-light.svg @@ -0,0 +1 @@ +Отключить \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/action-import-dark.svg b/artifacts/icon-family-v1/svg/action-import-dark.svg new file mode 100644 index 0000000..3530251 --- /dev/null +++ b/artifacts/icon-family-v1/svg/action-import-dark.svg @@ -0,0 +1 @@ +Импорт ключа \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/action-import-light.svg b/artifacts/icon-family-v1/svg/action-import-light.svg new file mode 100644 index 0000000..f0cc35f --- /dev/null +++ b/artifacts/icon-family-v1/svg/action-import-light.svg @@ -0,0 +1 @@ +Импорт ключа \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/action-logs-dark.svg b/artifacts/icon-family-v1/svg/action-logs-dark.svg new file mode 100644 index 0000000..736a22a --- /dev/null +++ b/artifacts/icon-family-v1/svg/action-logs-dark.svg @@ -0,0 +1 @@ +Логи \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/action-logs-light.svg b/artifacts/icon-family-v1/svg/action-logs-light.svg new file mode 100644 index 0000000..31ef4fd --- /dev/null +++ b/artifacts/icon-family-v1/svg/action-logs-light.svg @@ -0,0 +1 @@ +Логи \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/action-password-dark.svg b/artifacts/icon-family-v1/svg/action-password-dark.svg new file mode 100644 index 0000000..03d0d88 --- /dev/null +++ b/artifacts/icon-family-v1/svg/action-password-dark.svg @@ -0,0 +1 @@ +Логин и пароль \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/action-password-light.svg b/artifacts/icon-family-v1/svg/action-password-light.svg new file mode 100644 index 0000000..7d5d803 --- /dev/null +++ b/artifacts/icon-family-v1/svg/action-password-light.svg @@ -0,0 +1 @@ +Логин и пароль \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/action-quit-dark.svg b/artifacts/icon-family-v1/svg/action-quit-dark.svg new file mode 100644 index 0000000..5931470 --- /dev/null +++ b/artifacts/icon-family-v1/svg/action-quit-dark.svg @@ -0,0 +1 @@ +Выход \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/action-quit-light.svg b/artifacts/icon-family-v1/svg/action-quit-light.svg new file mode 100644 index 0000000..9e46d86 --- /dev/null +++ b/artifacts/icon-family-v1/svg/action-quit-light.svg @@ -0,0 +1 @@ +Выход \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/action-refresh-dark.svg b/artifacts/icon-family-v1/svg/action-refresh-dark.svg new file mode 100644 index 0000000..690e29c --- /dev/null +++ b/artifacts/icon-family-v1/svg/action-refresh-dark.svg @@ -0,0 +1 @@ +Обновить статус \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/action-refresh-light.svg b/artifacts/icon-family-v1/svg/action-refresh-light.svg new file mode 100644 index 0000000..f840a9d --- /dev/null +++ b/artifacts/icon-family-v1/svg/action-refresh-light.svg @@ -0,0 +1 @@ +Обновить статус \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/format-clock-dark.svg b/artifacts/icon-family-v1/svg/format-clock-dark.svg new file mode 100644 index 0000000..f10e260 --- /dev/null +++ b/artifacts/icon-family-v1/svg/format-clock-dark.svg @@ -0,0 +1 @@ +Щит-часы \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/format-clock-light.svg b/artifacts/icon-family-v1/svg/format-clock-light.svg new file mode 100644 index 0000000..7a27388 --- /dev/null +++ b/artifacts/icon-family-v1/svg/format-clock-light.svg @@ -0,0 +1 @@ +Щит-часы \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/format-ring-dark.svg b/artifacts/icon-family-v1/svg/format-ring-dark.svg new file mode 100644 index 0000000..c9f5b57 --- /dev/null +++ b/artifacts/icon-family-v1/svg/format-ring-dark.svg @@ -0,0 +1 @@ +Кольцо \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/format-ring-light.svg b/artifacts/icon-family-v1/svg/format-ring-light.svg new file mode 100644 index 0000000..2ad8d25 --- /dev/null +++ b/artifacts/icon-family-v1/svg/format-ring-light.svg @@ -0,0 +1 @@ +Кольцо \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/format-shield-dark.svg b/artifacts/icon-family-v1/svg/format-shield-dark.svg new file mode 100644 index 0000000..b8c2945 --- /dev/null +++ b/artifacts/icon-family-v1/svg/format-shield-dark.svg @@ -0,0 +1 @@ +Щит с прогрессом \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/format-shield-light.svg b/artifacts/icon-family-v1/svg/format-shield-light.svg new file mode 100644 index 0000000..044cda2 --- /dev/null +++ b/artifacts/icon-family-v1/svg/format-shield-light.svg @@ -0,0 +1 @@ +Щит с прогрессом \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/format-time-dark.svg b/artifacts/icon-family-v1/svg/format-time-dark.svg new file mode 100644 index 0000000..e821901 --- /dev/null +++ b/artifacts/icon-family-v1/svg/format-time-dark.svg @@ -0,0 +1 @@ +Щит + время2:18 \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/format-time-light.svg b/artifacts/icon-family-v1/svg/format-time-light.svg new file mode 100644 index 0000000..5a4ca85 --- /dev/null +++ b/artifacts/icon-family-v1/svg/format-time-light.svg @@ -0,0 +1 @@ +Щит + время2:18 \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/source-auto-dark.svg b/artifacts/icon-family-v1/svg/source-auto-dark.svg new file mode 100644 index 0000000..23aa703 --- /dev/null +++ b/artifacts/icon-family-v1/svg/source-auto-dark.svg @@ -0,0 +1 @@ +Автоматически \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/source-auto-light.svg b/artifacts/icon-family-v1/svg/source-auto-light.svg new file mode 100644 index 0000000..d614e9e --- /dev/null +++ b/artifacts/icon-family-v1/svg/source-auto-light.svg @@ -0,0 +1 @@ +Автоматически \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/source-local-dark.svg b/artifacts/icon-family-v1/svg/source-local-dark.svg new file mode 100644 index 0000000..55a3acf --- /dev/null +++ b/artifacts/icon-family-v1/svg/source-local-dark.svg @@ -0,0 +1 @@ +Ключ на Mac \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/source-local-light.svg b/artifacts/icon-family-v1/svg/source-local-light.svg new file mode 100644 index 0000000..bee121d --- /dev/null +++ b/artifacts/icon-family-v1/svg/source-local-light.svg @@ -0,0 +1 @@ +Ключ на Mac \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/source-manual-dark.svg b/artifacts/icon-family-v1/svg/source-manual-dark.svg new file mode 100644 index 0000000..93a9bbc --- /dev/null +++ b/artifacts/icon-family-v1/svg/source-manual-dark.svg @@ -0,0 +1 @@ +Вручную \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/source-manual-light.svg b/artifacts/icon-family-v1/svg/source-manual-light.svg new file mode 100644 index 0000000..e50acd6 --- /dev/null +++ b/artifacts/icon-family-v1/svg/source-manual-light.svg @@ -0,0 +1 @@ +Вручную \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/source-vault-dark.svg b/artifacts/icon-family-v1/svg/source-vault-dark.svg new file mode 100644 index 0000000..2344ddb --- /dev/null +++ b/artifacts/icon-family-v1/svg/source-vault-dark.svg @@ -0,0 +1 @@ +Bitwarden \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/source-vault-light.svg b/artifacts/icon-family-v1/svg/source-vault-light.svg new file mode 100644 index 0000000..cd83f1a --- /dev/null +++ b/artifacts/icon-family-v1/svg/source-vault-light.svg @@ -0,0 +1 @@ +Bitwarden \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/time-expired-dark.svg b/artifacts/icon-family-v1/svg/time-expired-dark.svg new file mode 100644 index 0000000..63df113 --- /dev/null +++ b/artifacts/icon-family-v1/svg/time-expired-dark.svg @@ -0,0 +1 @@ +Срок истёк \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/time-expired-light.svg b/artifacts/icon-family-v1/svg/time-expired-light.svg new file mode 100644 index 0000000..33aacb1 --- /dev/null +++ b/artifacts/icon-family-v1/svg/time-expired-light.svg @@ -0,0 +1 @@ +Срок истёк \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/time-half-dark.svg b/artifacts/icon-family-v1/svg/time-half-dark.svg new file mode 100644 index 0000000..a8ca7e3 --- /dev/null +++ b/artifacts/icon-family-v1/svg/time-half-dark.svg @@ -0,0 +1 @@ +50% прошло \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/time-half-light.svg b/artifacts/icon-family-v1/svg/time-half-light.svg new file mode 100644 index 0000000..850520c --- /dev/null +++ b/artifacts/icon-family-v1/svg/time-half-light.svg @@ -0,0 +1 @@ +50% прошло \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/time-hour-dark.svg b/artifacts/icon-family-v1/svg/time-hour-dark.svg new file mode 100644 index 0000000..0b510e0 --- /dev/null +++ b/artifacts/icon-family-v1/svg/time-hour-dark.svg @@ -0,0 +1 @@ +Остался час \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/time-hour-light.svg b/artifacts/icon-family-v1/svg/time-hour-light.svg new file mode 100644 index 0000000..c6a231f --- /dev/null +++ b/artifacts/icon-family-v1/svg/time-hour-light.svg @@ -0,0 +1 @@ +Остался час \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/time-quarter-dark.svg b/artifacts/icon-family-v1/svg/time-quarter-dark.svg new file mode 100644 index 0000000..26c0786 --- /dev/null +++ b/artifacts/icon-family-v1/svg/time-quarter-dark.svg @@ -0,0 +1 @@ +25% прошло \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/time-quarter-hour-dark.svg b/artifacts/icon-family-v1/svg/time-quarter-hour-dark.svg new file mode 100644 index 0000000..fe3b2b6 --- /dev/null +++ b/artifacts/icon-family-v1/svg/time-quarter-hour-dark.svg @@ -0,0 +1 @@ +Осталось 15 мин \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/time-quarter-hour-light.svg b/artifacts/icon-family-v1/svg/time-quarter-hour-light.svg new file mode 100644 index 0000000..33d247d --- /dev/null +++ b/artifacts/icon-family-v1/svg/time-quarter-hour-light.svg @@ -0,0 +1 @@ +Осталось 15 мин \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/time-quarter-light.svg b/artifacts/icon-family-v1/svg/time-quarter-light.svg new file mode 100644 index 0000000..e7f830b --- /dev/null +++ b/artifacts/icon-family-v1/svg/time-quarter-light.svg @@ -0,0 +1 @@ +25% прошло \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/time-start-dark.svg b/artifacts/icon-family-v1/svg/time-start-dark.svg new file mode 100644 index 0000000..3ff7020 --- /dev/null +++ b/artifacts/icon-family-v1/svg/time-start-dark.svg @@ -0,0 +1 @@ +Начало \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/time-start-light.svg b/artifacts/icon-family-v1/svg/time-start-light.svg new file mode 100644 index 0000000..7e56012 --- /dev/null +++ b/artifacts/icon-family-v1/svg/time-start-light.svg @@ -0,0 +1 @@ +Начало \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/time-three-quarter-dark.svg b/artifacts/icon-family-v1/svg/time-three-quarter-dark.svg new file mode 100644 index 0000000..f467dc7 --- /dev/null +++ b/artifacts/icon-family-v1/svg/time-three-quarter-dark.svg @@ -0,0 +1 @@ +75% прошло \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/time-three-quarter-light.svg b/artifacts/icon-family-v1/svg/time-three-quarter-light.svg new file mode 100644 index 0000000..50bff36 --- /dev/null +++ b/artifacts/icon-family-v1/svg/time-three-quarter-light.svg @@ -0,0 +1 @@ +75% прошло \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/time-unknown-dark.svg b/artifacts/icon-family-v1/svg/time-unknown-dark.svg new file mode 100644 index 0000000..44d6fbf --- /dev/null +++ b/artifacts/icon-family-v1/svg/time-unknown-dark.svg @@ -0,0 +1 @@ +Срок неизвестен \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/time-unknown-light.svg b/artifacts/icon-family-v1/svg/time-unknown-light.svg new file mode 100644 index 0000000..5f3434a --- /dev/null +++ b/artifacts/icon-family-v1/svg/time-unknown-light.svg @@ -0,0 +1 @@ +Срок неизвестен \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/vpn-connected-dark.svg b/artifacts/icon-family-v1/svg/vpn-connected-dark.svg new file mode 100644 index 0000000..6d1069e --- /dev/null +++ b/artifacts/icon-family-v1/svg/vpn-connected-dark.svg @@ -0,0 +1 @@ +Подключён \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/vpn-connected-light.svg b/artifacts/icon-family-v1/svg/vpn-connected-light.svg new file mode 100644 index 0000000..774bd6b --- /dev/null +++ b/artifacts/icon-family-v1/svg/vpn-connected-light.svg @@ -0,0 +1 @@ +Подключён \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/vpn-connecting-dark.svg b/artifacts/icon-family-v1/svg/vpn-connecting-dark.svg new file mode 100644 index 0000000..da29a25 --- /dev/null +++ b/artifacts/icon-family-v1/svg/vpn-connecting-dark.svg @@ -0,0 +1 @@ +Подключение \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/vpn-connecting-light.svg b/artifacts/icon-family-v1/svg/vpn-connecting-light.svg new file mode 100644 index 0000000..8d85b20 --- /dev/null +++ b/artifacts/icon-family-v1/svg/vpn-connecting-light.svg @@ -0,0 +1 @@ +Подключение \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/vpn-error-dark.svg b/artifacts/icon-family-v1/svg/vpn-error-dark.svg new file mode 100644 index 0000000..66b5b05 --- /dev/null +++ b/artifacts/icon-family-v1/svg/vpn-error-dark.svg @@ -0,0 +1 @@ +Ошибка \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/vpn-error-light.svg b/artifacts/icon-family-v1/svg/vpn-error-light.svg new file mode 100644 index 0000000..d21f449 --- /dev/null +++ b/artifacts/icon-family-v1/svg/vpn-error-light.svg @@ -0,0 +1 @@ +Ошибка \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/vpn-network-dark.svg b/artifacts/icon-family-v1/svg/vpn-network-dark.svg new file mode 100644 index 0000000..bd56bf9 --- /dev/null +++ b/artifacts/icon-family-v1/svg/vpn-network-dark.svg @@ -0,0 +1 @@ +Проблема сети \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/vpn-network-light.svg b/artifacts/icon-family-v1/svg/vpn-network-light.svg new file mode 100644 index 0000000..28e3850 --- /dev/null +++ b/artifacts/icon-family-v1/svg/vpn-network-light.svg @@ -0,0 +1 @@ +Проблема сети \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/vpn-off-dark.svg b/artifacts/icon-family-v1/svg/vpn-off-dark.svg new file mode 100644 index 0000000..c042ceb --- /dev/null +++ b/artifacts/icon-family-v1/svg/vpn-off-dark.svg @@ -0,0 +1 @@ +Отключён \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/vpn-off-light.svg b/artifacts/icon-family-v1/svg/vpn-off-light.svg new file mode 100644 index 0000000..e115160 --- /dev/null +++ b/artifacts/icon-family-v1/svg/vpn-off-light.svg @@ -0,0 +1 @@ +Отключён \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/vpn-reconnect-dark.svg b/artifacts/icon-family-v1/svg/vpn-reconnect-dark.svg new file mode 100644 index 0000000..672785a --- /dev/null +++ b/artifacts/icon-family-v1/svg/vpn-reconnect-dark.svg @@ -0,0 +1 @@ +Переподключение \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/vpn-reconnect-light.svg b/artifacts/icon-family-v1/svg/vpn-reconnect-light.svg new file mode 100644 index 0000000..2476c3c --- /dev/null +++ b/artifacts/icon-family-v1/svg/vpn-reconnect-light.svg @@ -0,0 +1 @@ +Переподключение \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/vpn-setup-dark.svg b/artifacts/icon-family-v1/svg/vpn-setup-dark.svg new file mode 100644 index 0000000..3a70a57 --- /dev/null +++ b/artifacts/icon-family-v1/svg/vpn-setup-dark.svg @@ -0,0 +1 @@ +Нужна настройка \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/vpn-setup-light.svg b/artifacts/icon-family-v1/svg/vpn-setup-light.svg new file mode 100644 index 0000000..cee8367 --- /dev/null +++ b/artifacts/icon-family-v1/svg/vpn-setup-light.svg @@ -0,0 +1 @@ +Нужна настройка \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/vpn-unknown-dark.svg b/artifacts/icon-family-v1/svg/vpn-unknown-dark.svg new file mode 100644 index 0000000..7dc67ca --- /dev/null +++ b/artifacts/icon-family-v1/svg/vpn-unknown-dark.svg @@ -0,0 +1 @@ +Статус неизвестен \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/vpn-unknown-light.svg b/artifacts/icon-family-v1/svg/vpn-unknown-light.svg new file mode 100644 index 0000000..4007c70 --- /dev/null +++ b/artifacts/icon-family-v1/svg/vpn-unknown-light.svg @@ -0,0 +1 @@ +Статус неизвестен \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/vpn-unlock-dark.svg b/artifacts/icon-family-v1/svg/vpn-unlock-dark.svg new file mode 100644 index 0000000..26a0eea --- /dev/null +++ b/artifacts/icon-family-v1/svg/vpn-unlock-dark.svg @@ -0,0 +1 @@ +Ожидаем вход \ No newline at end of file diff --git a/artifacts/icon-family-v1/svg/vpn-unlock-light.svg b/artifacts/icon-family-v1/svg/vpn-unlock-light.svg new file mode 100644 index 0000000..275f17d --- /dev/null +++ b/artifacts/icon-family-v1/svg/vpn-unlock-light.svg @@ -0,0 +1 @@ +Ожидаем вход \ No newline at end of file diff --git a/bin/lemana-vpn-import-yandex.py b/bin/lemana-vpn-import-yandex.py new file mode 100644 index 0000000..9c05a82 --- /dev/null +++ b/bin/lemana-vpn-import-yandex.py @@ -0,0 +1,239 @@ +#!/usr/bin/env python3 +"""Import one verified TOTP from a local Yandex Key backup into Keychain.""" +import argparse +import base64 +import binascii +from contextlib import ExitStack +import getpass +import json +import os +from pathlib import Path +import re +import shlex +import signal +import stat +import sys +import tempfile +import unicodedata +from urllib.parse import parse_qs, urlsplit + +MAX_BACKUP_BYTES = 4 * 1024 * 1024 + + +class ImportFailure(ValueError): + """Only fixed, secret-free messages may cross the CLI boundary.""" + + +def display_name(value, secrets=()): + value = "".join(c for c in value if not unicodedata.category(c).startswith("C")) + if "otpauth:" in value.lower() or any(secret and secret in value.upper() for secret in secrets): + return "" + return value[:120] + + +def read_backup(path): + try: + # Nonblocking open also lets us reject a mistakenly selected FIFO/device. + fd = os.open(path, os.O_RDONLY | os.O_NONBLOCK) + with os.fdopen(fd, "rb") as stream: + if not stat.S_ISREG(os.fstat(stream.fileno()).st_mode): + raise ImportFailure("Выберите обычный файл резервной копии.") + data = stream.read(MAX_BACKUP_BYTES + 1) + if len(data) > MAX_BACKUP_BYTES: + raise ImportFailure("Файл превышает лимит импорта 4 МиБ.") + entries = json.loads(data.decode("utf-8-sig")) + except (OSError, UnicodeError, ValueError) as error: + if isinstance(error, ImportFailure): + raise + raise ImportFailure("Не удалось прочитать локальный JSON-экспорт Яндекс Ключа.") from None + if not isinstance(entries, list) or not 1 <= len(entries) <= 1000: + raise ImportFailure("Ожидается резервная копия с 1–1000 записями.") + if any(not isinstance(entry, dict) or not isinstance(entry.get("techInfo"), str) for entry in entries): + raise ImportFailure("Неверная структура резервной копии Яндекс Ключа.") + return entries + + +def normalize_secret(value): + if not isinstance(value, str): + raise ImportFailure("Запись не содержит корректного секрета 2FA.") + value = value.strip().upper().rstrip("=") + if not re.fullmatch(r"[A-Z2-7]{16,1024}", value): + raise ImportFailure("Некорректный BASE32-секрет в выбранной записи.") + try: + decoded = base64.b32decode(value + "=" * (-len(value) % 8)) + except binascii.Error: + raise ImportFailure("Некорректный BASE32-секрет в выбранной записи.") from None + if base64.b32encode(decoded).decode().rstrip("=") != value: + raise ImportFailure("Некорректный BASE32-секрет в выбранной записи.") + return value + + +def selected_secret(entry): + try: + uri = urlsplit(entry["techInfo"]) + query = parse_qs(uri.query, keep_blank_values=True, max_num_fields=100) + except ValueError: + raise ImportFailure("Некорректные параметры OTP в выбранной записи.") from None + if uri.scheme != "otpauth" or uri.netloc != "totp" or uri.fragment: + raise ImportFailure("Поддерживается только TOTP; HOTP и собственные коды Яндекса не поддерживаются.") + if set(query) - {"secret", "algorithm", "digits", "period", "issuer", "account_id", "created_at", "creation_type", "image", "name", "uid"}: + raise ImportFailure("Выбранная запись содержит неподдерживаемые параметры OTP.") + for key in ("secret", "algorithm", "digits", "period"): + if key in query and len(query[key]) != 1: + raise ImportFailure("В записи повторяются параметры OTP.") + if (query.get("algorithm", ["SHA1"])[0].upper() != "SHA1" + or query.get("digits", ["6"])[0] != "6" + or query.get("period", ["30"])[0] != "30" + or "counter" in query): + raise ImportFailure("Поддерживается только TOTP: SHA1, 6 цифр, период 30 секунд.") + secret = normalize_secret(query.get("secret", [""])[0]) + if "secret" in entry and normalize_secret(entry["secret"]) != secret: + raise ImportFailure("Секрет и параметры выбранной записи не совпадают.") + return secret + + +def activate(secret, username, config_file): + import keyring + + # Stage settings before touching Keychain; retain all unrelated local settings. + text = config_file.read_text() if config_file.exists() else "" + saved = None + for line in text.splitlines(): + match = re.fullmatch(r'(?:export[ \t]+)?LEMANA_VPN_USERNAME=("(?:\\.|[^"\\])*"|\'[^\']*\'|[^\n]*)[ \t]*(?:#.*)?', line) + if match: + raw = match[1] + if raw.startswith('"'): + saved = re.sub(r'\\([$`"\\])', lambda m: m[1], raw[1:-1]) + else: + values = shlex.split(raw, comments=True) + saved = values[0] if len(values) == 1 else None + if saved != username: + raise ImportFailure("Сохранённый LDAP username изменился или не настроен. Сначала выполните vpn --configure-login.") + original_text = text + for key, value in (("LEMANA_VPN_MODE", "keychain-auto"), ("LEMANA_VPN_LOCAL_OTP", "1"), + ("LEMANA_VPN_AUTO_SOURCE", "keychain"), ("LEMANA_VPN_AUTH_PROFILE", "auto"), + ("LEMANA_VPN_CREDENTIAL_SOURCE", "keychain"), ("LEMANA_VPN_USE_BITWARDEN", "0")): + assignment = f'{key}="{value}"\n' + pattern = r"(?m)^(?:export[ \t]+)?" + key + r"=[^\n]*(?:\n|$)" + text = re.sub(pattern, "", text) + text = text.rstrip("\n") + "\n" + assignment + config_file.parent.mkdir(parents=True, exist_ok=True) + fd, staging = tempfile.mkstemp(prefix=".otp-env-", dir=config_file.parent) + try: + with os.fdopen(fd, "w") as stream: + stream.write(text) + account = "totp/" + username + previous = keyring.get_password("openconnect-lite", account) + try: + keyring.set_password("openconnect-lite", account, secret) + if keyring.get_password("openconnect-lite", account) != secret: + raise ImportFailure("Keychain не подтвердил сохранение секрета; локальный код не включён.") + if config_file.read_text() != original_text: + raise ImportFailure("Настройки изменились во время импорта; повторите импорт.") + os.replace(staging, config_file) + except BaseException: + if not os.path.exists(staging): + # replace is the commit point: both stores now contain the new state. + raise ImportFailure("Настройка уже сохранена. Проверьте её командой vpn --status.") from None + # An interrupted activation must not silently replace working credentials. + try: + if previous is None: + if keyring.get_password("openconnect-lite", account) is not None: + keyring.delete_password("openconnect-lite", account) + else: + keyring.set_password("openconnect-lite", account, previous) + if keyring.get_password("openconnect-lite", account) != previous: + raise RuntimeError + except BaseException: + raise ImportFailure("Импорт не завершён, вернуть прежний секрет не удалось. Проверьте запись 2FA в Keychain.") from None + raise + finally: + if os.path.exists(staging): + os.unlink(staging) + + +def configure(username, config_file, ask, ask_secret, say): + import pyotp + + say("В Яндекс Ключе: Настройки → Резервная копия данных → Сохранить в файл.") + entries = read_backup(Path(ask("Путь к файлу резервной копии: ").strip()).expanduser()) + secrets = set() + for entry in entries: + if isinstance(entry.get("secret"), str) and entry["secret"]: + secrets.add(entry["secret"].strip().upper().rstrip("=")) + try: + for value in parse_qs(urlsplit(entry["techInfo"]).query, max_num_fields=100).get("secret", []): + if value: + secrets.add(value.strip().upper().rstrip("=")) + except ValueError: + pass + labels = [] + for index, entry in enumerate(entries, 1): + name = entry.get("name", "") + label = display_name(name, secrets) if isinstance(name, str) else "" + labels.append(label or f"Запись {index}") + say(f"{index}) {labels[-1]}") + choice = ask("Номер записи Lemana/VPN (Enter — отмена): ").strip() + if not re.fullmatch(r"[0-9]{1,4}", choice) or not 1 <= int(choice) <= len(entries): + raise ImportFailure("Запись не выбрана; настройки не изменены.") + entry = entries[int(choice) - 1] + secret = selected_secret(entry) + say(f"Запись: {labels[int(choice) - 1]}; LDAP: {display_name(username)}.") + say("Будет включён автоматический вход с ключом на этом Mac: скрытый браузер, подстановка данных и отправка формы без Bitwarden.") + code = ask_secret("Введите текущие 6 цифр из этой записи на телефоне для проверки и сохранения: ").strip() + if not re.fullmatch(r"[0-9]{6}", code) or not pyotp.TOTP(secret).verify(code, valid_window=1): + raise ImportFailure("Код не совпал. Проверьте выбранную запись и время на устройствах; настройки не изменены.") + activate(secret, username, config_file) + say("Готово: одноразовый код сохранён в Keychain и будет подставляться при следующем подключении.") + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--username", required=True) + parser.add_argument("--config", required=True, type=Path) + args = parser.parse_args() + + def interrupted(_signum, _frame): + raise KeyboardInterrupt + + signal.signal(signal.SIGTERM, interrupted) + try: + import toml + from xdg.BaseDirectory import load_first_config + + # Match the actual openconnect-lite read path, including XDG overrides. + config_dir = load_first_config("openconnect-lite") + if not config_dir or toml.load(Path(config_dir) / "config.toml").get("credentials", {}).get("username") != args.username: + raise ImportFailure("LDAP username в профиле SSO отличается. Согласуйте логин через vpn --configure-login или установщик.") + with ExitStack() as handles: + terminal_input, terminal = sys.stdin, sys.stderr + if not sys.stdin.isatty(): + terminal_fd = os.open("/dev/tty", os.O_RDWR | os.O_NOCTTY) + terminal_input = handles.enter_context(os.fdopen(os.dup(terminal_fd), "r", encoding="utf-8")) + terminal = handles.enter_context(os.fdopen(terminal_fd, "w", encoding="utf-8")) + def ask(prompt): + terminal.write(prompt) + terminal.flush() + line = terminal_input.readline() + if not line: + raise EOFError + return line.rstrip("\n") + + configure(args.username, args.config, ask, + lambda prompt: getpass.getpass(prompt, stream=terminal), + lambda message: print(message, file=terminal, flush=True)) + except ImportFailure as error: + print(str(error), file=sys.stderr) + return 1 + except (EOFError, KeyboardInterrupt): + print("Импорт отменён.", file=sys.stderr) + return 1 + except Exception: + # Backend/JSON exceptions may contain sensitive data; never print them. + print("Не удалось завершить импорт. Запустите команду в Terminal и проверьте доступ к файлу и Keychain.", file=sys.stderr) + return 1 + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/bin/vpn-lemanapro.sh b/bin/vpn-lemanapro.sh index e14a1c6..bc9b094 100755 --- a/bin/vpn-lemanapro.sh +++ b/bin/vpn-lemanapro.sh @@ -7,11 +7,15 @@ OC_CONFIG_DIR="${OPENCONNECT_LITE_CONFIG_DIR:-$HOME/.config/openconnect-lite}" _ENV_LEMANA_VPN_USERNAME="${LEMANA_VPN_USERNAME+x}${LEMANA_VPN_USERNAME-}" _ENV_LEMANA_VPN_BW_ITEM="${LEMANA_VPN_BW_ITEM+x}${LEMANA_VPN_BW_ITEM-}" +_ENV_LEMANA_VPN_MODE="${LEMANA_VPN_MODE+x}${LEMANA_VPN_MODE-}" _ENV_LEMANA_VPN_AUTH_PROFILE="${LEMANA_VPN_AUTH_PROFILE+x}${LEMANA_VPN_AUTH_PROFILE-}" _ENV_LEMANA_VPN_USE_BITWARDEN="${LEMANA_VPN_USE_BITWARDEN+x}${LEMANA_VPN_USE_BITWARDEN-}" _ENV_LEMANA_VPN_CREDENTIAL_SOURCE="${LEMANA_VPN_CREDENTIAL_SOURCE+x}${LEMANA_VPN_CREDENTIAL_SOURCE-}" _ENV_LEMANA_VPN_USE_TOUCHID="${LEMANA_VPN_USE_TOUCHID+x}${LEMANA_VPN_USE_TOUCHID-}" _ENV_LEMANA_VPN_DNS_CLEANUP="${LEMANA_VPN_DNS_CLEANUP+x}${LEMANA_VPN_DNS_CLEANUP-}" +_ENV_LEMANA_VPN_LOG_MAX_BYTES="${LEMANA_VPN_LOG_MAX_BYTES+x}${LEMANA_VPN_LOG_MAX_BYTES-}" +_ENV_LEMANA_VPN_LOCAL_OTP="${LEMANA_VPN_LOCAL_OTP+x}${LEMANA_VPN_LOCAL_OTP-}" +_ENV_LEMANA_VPN_AUTO_SOURCE="${LEMANA_VPN_AUTO_SOURCE+x}${LEMANA_VPN_AUTO_SOURCE-}" if [[ -f "$CONFIG_FILE" ]]; then # shellcheck disable=SC1090 @@ -20,11 +24,15 @@ fi [[ "${_ENV_LEMANA_VPN_USERNAME:0:1}" == "x" ]] && LEMANA_VPN_USERNAME="${_ENV_LEMANA_VPN_USERNAME:1}" [[ "${_ENV_LEMANA_VPN_BW_ITEM:0:1}" == "x" ]] && LEMANA_VPN_BW_ITEM="${_ENV_LEMANA_VPN_BW_ITEM:1}" +[[ "${_ENV_LEMANA_VPN_MODE:0:1}" == "x" ]] && LEMANA_VPN_MODE="${_ENV_LEMANA_VPN_MODE:1}" [[ "${_ENV_LEMANA_VPN_AUTH_PROFILE:0:1}" == "x" ]] && LEMANA_VPN_AUTH_PROFILE="${_ENV_LEMANA_VPN_AUTH_PROFILE:1}" [[ "${_ENV_LEMANA_VPN_USE_BITWARDEN:0:1}" == "x" ]] && LEMANA_VPN_USE_BITWARDEN="${_ENV_LEMANA_VPN_USE_BITWARDEN:1}" [[ "${_ENV_LEMANA_VPN_CREDENTIAL_SOURCE:0:1}" == "x" ]] && LEMANA_VPN_CREDENTIAL_SOURCE="${_ENV_LEMANA_VPN_CREDENTIAL_SOURCE:1}" [[ "${_ENV_LEMANA_VPN_USE_TOUCHID:0:1}" == "x" ]] && LEMANA_VPN_USE_TOUCHID="${_ENV_LEMANA_VPN_USE_TOUCHID:1}" [[ "${_ENV_LEMANA_VPN_DNS_CLEANUP:0:1}" == "x" ]] && LEMANA_VPN_DNS_CLEANUP="${_ENV_LEMANA_VPN_DNS_CLEANUP:1}" +[[ "${_ENV_LEMANA_VPN_LOG_MAX_BYTES:0:1}" == "x" ]] && LEMANA_VPN_LOG_MAX_BYTES="${_ENV_LEMANA_VPN_LOG_MAX_BYTES:1}" +[[ "${_ENV_LEMANA_VPN_LOCAL_OTP:0:1}" == "x" ]] && LEMANA_VPN_LOCAL_OTP="${_ENV_LEMANA_VPN_LOCAL_OTP:1}" +[[ "${_ENV_LEMANA_VPN_AUTO_SOURCE:0:1}" == "x" ]] && LEMANA_VPN_AUTO_SOURCE="${_ENV_LEMANA_VPN_AUTO_SOURCE:1}" OC_VENV="${LEMANA_VPN_OC_VENV:-$HOME/.local/pipx/venvs/openconnect-lite}" OC_PYTHON="${LEMANA_VPN_OC_PYTHON:-$OC_VENV/bin/python}" @@ -32,6 +40,13 @@ OC_BIN="${LEMANA_VPN_OC_BIN:-$HOME/.local/bin/openconnect-lite}" BW_ITEM_NAME="${LEMANA_VPN_BW_ITEM:-LM LDAP}" KC_USERNAME="${LEMANA_VPN_USERNAME:-}" KC_FP="${LEMANA_VPN_KEYCHAIN_FINGERPRINT:-$HOME/bin/keychain-fingerprint}" +MODE="${LEMANA_VPN_MODE:-}" +LOCAL_OTP="${LEMANA_VPN_LOCAL_OTP-0}" +AUTO_SOURCE="${LEMANA_VPN_AUTO_SOURCE:-keychain}" +case "$LOCAL_OTP" in + 0|1) ;; + *) printf 'LEMANA_VPN_LOCAL_OTP must be 0 or 1.\n' >&2; exit 2 ;; +esac AUTH_PROFILE="${LEMANA_VPN_AUTH_PROFILE:-manual}" CREDENTIAL_SOURCE="${LEMANA_VPN_CREDENTIAL_SOURCE:-}" if [[ -z "$CREDENTIAL_SOURCE" ]]; then @@ -41,32 +56,7 @@ if [[ -z "$CREDENTIAL_SOURCE" ]]; then CREDENTIAL_SOURCE="none" fi fi - -case "$AUTH_PROFILE" in - manual|saved-login|saved-totp|auto) ;; - *) - printf 'Unknown auth profile: %s. Use manual, saved-login, saved-totp, or auto.\n' "$AUTH_PROFILE" >&2 - exit 2 - ;; -esac - -case "$CREDENTIAL_SOURCE" in - none|bitwarden|keychain) ;; - *) - printf 'Unknown credential source: %s. Use none, bitwarden, or keychain.\n' "$CREDENTIAL_SOURCE" >&2 - exit 2 - ;; -esac - -if [[ "$CREDENTIAL_SOURCE" == "bitwarden" ]]; then - USE_BITWARDEN="1" -else - USE_BITWARDEN="0" -fi USE_TOUCHID="${LEMANA_VPN_USE_TOUCHID:-0}" -if [[ "$CREDENTIAL_SOURCE" != "bitwarden" ]]; then - USE_TOUCHID="0" -fi 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}" @@ -79,6 +69,11 @@ STATUS_FILE="$STATUS_DIR/status.json" PATCH_BACKUP_DIR="${LEMANA_VPN_PATCH_BACKUP_DIR:-$CONFIG_DIR/patch-backups}" CONNECT_LOG_DIR="${LEMANA_VPN_LOG_DIR:-$HOME/Library/Logs}" CONNECT_LOG_FILE="${LEMANA_VPN_CONNECT_LOG:-$CONNECT_LOG_DIR/LemanaVPN-openconnect-lite.log}" +LOG_MAX_BYTES="${LEMANA_VPN_LOG_MAX_BYTES-5242880}" +if [[ ! "$LOG_MAX_BYTES" =~ ^[1-9][0-9]{0,8}$ ]]; then + printf 'LEMANA_VPN_LOG_MAX_BYTES must be an integer from 1 to 999999999.\n' >&2 + exit 2 +fi CONNECT_WAIT_SECONDS="${LEMANA_VPN_CONNECT_WAIT_SECONDS:-20}" OC_RUNTIME_XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}" MANUAL_XDG_CONFIG_HOME="" @@ -86,68 +81,139 @@ MANUAL_XDG_CONFIG_HOME="" DEBUG=false JSON_MODE=false STATUS_MODE=false +REPAIR_DNS_MODE=false +SESSION_ID="" +STOP_SESSION="" +RESTART_SESSION="" +RESTART_ATTEMPT="" CONFIGURE_LOGIN_MODE=false CONFIGURE_KEYCHAIN_MODE=false +IMPORT_YANDEX_KEY_MODE=false +SET_AUTH="" PATCH_ONLY_MODE=false CONNECT_MODE="${LEMANA_VPN_MODE:-}" +FULL_MANUAL_OVERRIDE=false + +_normalize_public_mode() { + if [[ -z "${MODE:-}" ]]; then + case "$CREDENTIAL_SOURCE:$AUTH_PROFILE" in + bitwarden:*|*:auto) + MODE="bitwarden-auto" + ;; + *) + MODE="manual-keychain" + ;; + esac + fi + + if [[ "$MODE" == "manual-keychain" && "$LOCAL_OTP" == "1" ]]; then + MODE="keychain-auto" + fi + case "$MODE" in + manual-keychain) + LOCAL_OTP="0" + AUTH_PROFILE="saved-login" + CREDENTIAL_SOURCE="keychain" + USE_BITWARDEN="0" + USE_TOUCHID="0" + ;; + keychain-auto) + AUTH_PROFILE="auto" + CREDENTIAL_SOURCE="keychain" + LOCAL_OTP="1" + AUTO_SOURCE="keychain" + USE_BITWARDEN="0" + USE_TOUCHID="0" + ;; + bitwarden-auto) + LOCAL_OTP="0" + AUTO_SOURCE="bitwarden" + AUTH_PROFILE="auto" + CREDENTIAL_SOURCE="bitwarden" + USE_BITWARDEN="1" + USE_TOUCHID="${LEMANA_VPN_USE_TOUCHID:-1}" + ;; + *) + printf 'Unknown mode: %s. Use manual-keychain, keychain-auto or bitwarden-auto.\n' "$MODE" >&2 + exit 2 + ;; + esac + case "$AUTO_SOURCE" in + keychain|bitwarden) ;; + *) printf 'LEMANA_VPN_AUTO_SOURCE must be keychain or bitwarden.\n' >&2; exit 2 ;; + esac +} for arg in "$@"; do case "$arg" in --debug) DEBUG=true ;; --json) JSON_MODE=true ;; --status) STATUS_MODE=true ;; + --repair-dns) REPAIR_DNS_MODE=true ;; + --session-id=*) SESSION_ID="${arg#--session-id=}"; [[ "$SESSION_ID" =~ ^[a-f0-9-]{36}$ ]] || exit 2 ;; + --stop-session=*) STOP_SESSION="${arg#--stop-session=}"; [[ "$STOP_SESSION" =~ ^[a-f0-9-]{36}$ ]] || exit 2 ;; + --restart-session=*) RESTART_SESSION="${arg#--restart-session=}"; [[ "$RESTART_SESSION" =~ ^[a-f0-9-]{36}$ ]] || exit 2 ;; + --restart-attempt=*) RESTART_ATTEMPT="${arg#--restart-attempt=}"; [[ "$RESTART_ATTEMPT" =~ ^[a-f0-9-]{36}$ ]] || exit 2 ;; --configure-login) CONFIGURE_LOGIN_MODE=true ;; --configure-keychain) CONFIGURE_KEYCHAIN_MODE=true ;; + --import-yandex-key) IMPORT_YANDEX_KEY_MODE=true ;; + --set-auth=*) SET_AUTH="${arg#--set-auth=}"; case "$SET_AUTH" in manual|auto|keychain|bitwarden) ;; *) printf 'Unknown auth setting. Use manual, auto, keychain or bitwarden.\n' >&2; exit 2 ;; esac ;; --patch-only) PATCH_ONLY_MODE=true ;; - --auto|auto) AUTH_PROFILE="auto"; CONNECT_MODE="auto" ;; - --manual|manual|--manual-sso) AUTH_PROFILE="saved-totp"; CONNECT_MODE="saved-totp" ;; - --saved-login|saved-login|--login-only) AUTH_PROFILE="saved-login"; CONNECT_MODE="saved-login" ;; - --manual-full|manual-full|--manual-no-autofill) AUTH_PROFILE="manual"; CONNECT_MODE="manual-full" ;; + --mode=manual-keychain|manual-keychain) MODE="manual-keychain"; CONNECT_MODE="manual-keychain"; LOCAL_OTP="0" ;; + --mode=keychain-auto|keychain-auto) MODE="keychain-auto"; CONNECT_MODE="keychain-auto" ;; + --mode=bitwarden-auto|bitwarden-auto) MODE="bitwarden-auto"; CONNECT_MODE="bitwarden-auto" ;; + --auto|auto) MODE="bitwarden-auto"; CONNECT_MODE="bitwarden-auto" ;; + --manual|manual|--manual-sso|--saved-login|saved-login|--login-only) MODE="manual-keychain"; CONNECT_MODE="manual-keychain"; LOCAL_OTP="0" ;; + --manual-full|manual-full|--manual-no-autofill) MODE="manual-keychain"; CONNECT_MODE="manual-keychain"; LOCAL_OTP="0"; FULL_MANUAL_OVERRIDE=true ;; --help|-h) cat <<'HELP' -Usage: vpn-lemanapro.sh [--auto|--manual|--saved-login|--manual-full] [--debug] [--json] [--status] [--configure-login] [--configure-keychain] [--patch-only] +Usage: vpn-lemanapro.sh [manual-keychain|keychain-auto|bitwarden-auto] [--manual-full] [--debug] [--json] [--status] [--configure-login] [--configure-keychain] [--import-yandex-key] [--set-auth=VALUE] [--patch-only] --status Show current VPN status without connecting --status --json Show current VPN status as JSON - --auto Hidden browser, auto-fill and auto-submit - --manual Visible browser, saved fields auto-filled, do not press submit - --saved-login Visible browser, saved username/password only, OTP manual - --manual-full Visible browser, no auto-fill, do not press submit (default on fresh install) + --repair-dns Restore recorded orphaned VPN DNS without connecting + manual-keychain Visible browser, saved username/password, OTP entered manually + keychain-auto Automatic login using the key saved on this Mac + bitwarden-auto Automatic login using Bitwarden + optional Touch ID + --auto Compatibility alias for bitwarden-auto + --manual Compatibility alias for manual-keychain + --saved-login Compatibility alias for manual-keychain + --manual-full Diagnostic fallback: visible browser, no auto-fill, no submit --manual-no-autofill Compatibility alias for --manual-full - --manual-sso Compatibility alias for --manual + --manual-sso Compatibility alias for manual-keychain --debug Passthrough debug logs; also shows browser in auto mode --json Emit JSON Lines events for UI wrappers - --configure-login Save LDAP username/password in macOS Keychain; OTP remains manual + --configure-login Save LDAP username/password in macOS Keychain --configure-keychain Save LDAP password plus permanent 2FA setup code or otpauth:// URI + --import-yandex-key Import and verify a local Yandex Key backup; enable automatic login + --set-auth=VALUE Save manual, auto, keychain or bitwarden for future connections --patch-only Apply openconnect-lite runtime patches and exit HELP exit 0 ;; + *) + printf 'Unknown argument: %s. Use --help.\n' "$arg" >&2 + exit 2 + ;; esac done +if [[ -n "$RESTART_ATTEMPT" && -z "$RESTART_SESSION" ]]; then exit 2; fi + case "$CONNECT_MODE" in "") ;; - manual-full) - AUTH_PROFILE="manual" + manual-keychain|keychain-auto|bitwarden-auto) + MODE="$CONNECT_MODE" ;; - manual) - AUTH_PROFILE="saved-totp" - ;; - saved-login|saved-totp|auto) - AUTH_PROFILE="$CONNECT_MODE" - ;; -esac - -case "$AUTH_PROFILE" in - manual|saved-login|saved-totp|auto) ;; *) - printf 'Unknown auth profile: %s. Use manual, saved-login, saved-totp, or auto.\n' "$AUTH_PROFILE" >&2 + printf 'Unknown mode: %s. Use manual-keychain, keychain-auto or bitwarden-auto.\n' "$CONNECT_MODE" >&2 exit 2 ;; esac +_normalize_public_mode + _emit() { local json="$1" human="$2" if $JSON_MODE; then @@ -212,16 +278,44 @@ PY } _prepare_connection_log() { - mkdir -p "$CONNECT_LOG_DIR" - { - printf '\n==== Lemana VPN openconnect-lite session %s ====\n' "$(date '+%Y-%m-%d %H:%M:%S')" - printf 'Command: %s\n' "$OC_BIN" - } >> "$CONNECT_LOG_FILE" - chmod 600 "$CONNECT_LOG_FILE" 2>/dev/null || true + _log_connection_line "==== Lemana VPN openconnect-lite session; command: $OC_BIN ====" +} + +_connection_log_failed=false +_connection_log_ready=false + +_append_connection_log() { + local entry="$1" size archive_size=0 + local LC_ALL=C + if ! ${_connection_log_ready:-false}; then + (umask 077; mkdir -p "$(dirname "$CONNECT_LOG_FILE")" && touch "$CONNECT_LOG_FILE") || return 1 + chmod 600 "$CONNECT_LOG_FILE" || return 1 + if [[ -f "$CONNECT_LOG_FILE.1" ]]; then + chmod 600 "$CONNECT_LOG_FILE.1" || return 1 + archive_size="$(wc -c < "$CONNECT_LOG_FILE.1")" || return 1 + fi + _connection_log_ready=true + fi + size="$(wc -c < "$CONNECT_LOG_FILE")" || return 1 + if (( size + ${#entry} > LOG_MAX_BYTES || archive_size > LOG_MAX_BYTES )); then + # Copy only the bounded tail, including when upgrading a multi-GB legacy log. + (umask 077; tail -c "$LOG_MAX_BYTES" "$CONNECT_LOG_FILE" > "$CONNECT_LOG_FILE.1") || return 1 + : > "$CONNECT_LOG_FILE" || return 1 + fi + if (( ${#entry} > LOG_MAX_BYTES )); then + entry="${entry: -LOG_MAX_BYTES}" + fi + printf '%s' "$entry" >> "$CONNECT_LOG_FILE" } _log_connection_line() { - printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$1" >> "$CONNECT_LOG_FILE" + $_connection_log_failed && return 0 + local entry + printf -v entry '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$1" + if ! _append_connection_log "$entry" 2>/dev/null; then + printf 'Cannot write VPN log: %s; continuing without file logging.\n' "$CONNECT_LOG_FILE" >&2 + _connection_log_failed=true + fi } _show_connection_log_tail() { @@ -279,6 +373,28 @@ _module_bool() { fi } +_dns_recovery_supported() { + # Never probe an old helper by executing it: old versions ignored arguments. + [[ -x "$DNS_CLEANUP" ]] && grep -qx '# LEMANA_DNS_PROTOCOL=2' "$DNS_CLEANUP" +} + +_session_stop_supported() { + [[ -x "$DNS_CLEANUP" ]] && grep -qx '# LEMANA_SESSION_PROTOCOL=1' "$DNS_CLEANUP" +} + +_stop_session() { + local result=error code=1 + if _session_stop_supported && [[ "$STOP_SESSION" =~ ^[a-f0-9-]{36}$ ]]; then + if result="$(sudo -n "$DNS_CLEANUP" --stop "$STOP_SESSION")" && [[ "$result" == stopping ]]; then + result=stopping; code=0 + else + result=error + fi + fi + _emit "{\"event\":\"session_stop\",\"result\":\"$result\"}" "Session stop: $result" + return "$code" +} + _patches_active() { local wep authp wep="$(_find_webengine_process)" @@ -289,6 +405,7 @@ _patches_active() { && grep -q 'new RegExp' "$wep" \ && grep -q 'LEMANA_VPN_AUTOFILL_DISABLE' "$wep" \ && grep -q 'LEMANA_VPN_AUTOFILL_CLICK' "$wep" \ + && grep -q 'class LemanaVPNPage(QWebEnginePage)' "$wep" \ && ! grep -Eq '__lemanaVpnClicked|valueSetter|ScriptWorldId.MainWorld' "$wep" \ && grep -q 'self.session.get(self.host.vpn_url, allow_redirects=False)' "$authp" \ && grep -q 'response.headers.get("Location")' "$authp" \ @@ -299,51 +416,85 @@ _keychain_has() { security find-generic-password -s "$1" -a "$2" >/dev/null 2>&1 } +_set_auth() { + CONFIG_FILE="$CONFIG_FILE" AUTH_CHOICE="$SET_AUTH" AUTO_SOURCE="$AUTO_SOURCE" python3 - <<'PY' +import os +from pathlib import Path +import re +import tempfile + +choice = os.environ["AUTH_CHOICE"] +source = os.environ["AUTO_SOURCE"] if choice in ("manual", "auto") else choice +mode = "manual-keychain" if choice == "manual" else source + "-auto" +settings = { + "LEMANA_VPN_MODE": mode, + "LEMANA_VPN_LOCAL_OTP": "1" if mode == "keychain-auto" else "0", + "LEMANA_VPN_AUTO_SOURCE": source, + "LEMANA_VPN_AUTH_PROFILE": "saved-login" if choice == "manual" else "auto", + "LEMANA_VPN_CREDENTIAL_SOURCE": "bitwarden" if mode == "bitwarden-auto" else "keychain", + "LEMANA_VPN_USE_BITWARDEN": "1" if mode == "bitwarden-auto" else "0", +} +path = Path(os.environ["CONFIG_FILE"]) +staging = None +try: + text = path.read_text() if path.exists() else "" + for key in settings: + text = re.sub(r"(?m)^(?:export[ \t]+)?" + key + r"=[^\n]*(?:\n|$)", "", text) + text = text.rstrip("\n") + "\n" + "".join(f'{key}="{value}"\n' for key, value in settings.items()) + path.parent.mkdir(parents=True, exist_ok=True) + fd, staging = tempfile.mkstemp(prefix=".auth-env-", dir=path.parent) + with os.fdopen(fd, "w") as stream: + stream.write(text) + os.replace(staging, path) +except OSError: + raise SystemExit("Не удалось сохранить способ входа. Проверьте доступ к настройкам Lemana VPN.") from None +finally: + if staging and os.path.exists(staging): + os.unlink(staging) +print('Способ входа сохранён. Настройка применяется при следующем подключении.') +PY +} + _app_menu_json() { local login_ready="$1" keychain_ready="$2" local install_label configured_mode available_modes setup_hint_json - configured_mode="$AUTH_PROFILE" + configured_mode="$MODE" setup_hint_json="null" - case "$AUTH_PROFILE" in - manual) - install_label="Режим: полностью вручную" - available_modes='"configured"' - ;; - saved-login) + case "$MODE" in + manual-keychain) if [[ "$login_ready" == "true" ]]; then - install_label="Режим: логин и пароль сохранены" - available_modes='"configured","manual-full"' + install_label="Режим: ручной вход, логин и пароль сохранены" + available_modes='"configured","bitwarden-auto"' else - install_label="Режим: логин и пароль не настроены" - available_modes='"manual-full"' + install_label="Режим: ручной вход, логин и пароль не настроены" + available_modes='"configured","bitwarden-auto"' setup_hint_json='"Настройте в Terminal: vpn --configure-login"' fi ;; - saved-totp) - if [[ "$keychain_ready" == "true" ]]; then - install_label="Режим: сохранённые данные без автоотправки" - available_modes='"configured","saved-login","manual-full","auto"' - else - install_label="Режим: сохранённые данные не настроены" - available_modes='"manual-full"' - setup_hint_json='"Настройте в Terminal: vpn --configure-keychain"' + keychain-auto) + install_label="Автоматически · ключ на этом Mac" + available_modes='"configured","manual-keychain"' + if [[ "$login_ready" != "true" ]]; then + setup_hint_json='"Настройте логин и пароль: vpn --configure-login"' + elif [[ "$keychain_ready" != "true" ]]; then + setup_hint_json='"Импортируйте код: vpn --import-yandex-key"' fi ;; - auto) + bitwarden-auto) if [[ "$keychain_ready" == "true" ]]; then - install_label="Режим: автоматический вход" - available_modes='"configured","saved-totp","saved-login","manual-full"' + install_label="Автоматически · Bitwarden" + available_modes='"configured","manual-keychain"' else - install_label="Режим: автоматический вход не настроен" - available_modes='"manual-full"' - setup_hint_json='"Настройте в Terminal: vpn --configure-keychain"' + install_label="Автоматически · Bitwarden, данные будут синхронизированы" + available_modes='"configured","manual-keychain"' + setup_hint_json='"Bitwarden синхронизирует данные при подключении; если не сработает, проверьте bw login"' fi ;; *) install_label="Режим: неизвестен" - configured_mode="manual" + configured_mode="manual-keychain" available_modes='"configured"' setup_hint_json='"Обновите Lemana VPN через install.sh"' ;; @@ -358,6 +509,7 @@ _module_status_json() { local app_installed app_autostart local config_present oc_config_present patch_backup_present patches_active keychain_password keychain_totp_seed local credential_keychain_ready credential_login_ready app_menu_json + local mode_label mode_ready mode_hint_json auth_kind auth_detail openconnect_installed="$(_module_bool command -v openconnect)" openconnect_lite_installed="$(_module_bool test -x "$OC_BIN")" bitwarden_installed="$(_module_bool command -v bw)" @@ -375,11 +527,51 @@ _module_status_json() { credential_login_ready="$([[ "$keychain_password" == "true" ]] && printf true || printf false)" app_menu_json="$(_app_menu_json "$credential_login_ready" "$credential_keychain_ready")" - printf '{"core":{"openconnect":%s,"openconnect_lite":%s,"config":%s,"openconnect_lite_config":%s},"credentials":{"source":"%s","auth_profile":"%s","login_ready":%s,"keychain_ready":%s},"app_menu":%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}}' \ + case "$MODE" in + manual-keychain) + mode_label="Вручную" + auth_kind="manual" + auth_detail="Логин и пароль с этого Mac, код вводится вручную" + mode_ready="$credential_login_ready" + mode_hint_json="$([[ "$credential_login_ready" == "true" ]] && printf null || printf '"Настройте логин и пароль: vpn --configure-login"')" + ;; + keychain-auto) + mode_label="Автоматически · ключ на этом Mac" + auth_kind="auto" + auth_detail="Логин, пароль и код с этого Mac; вход без ручного ввода" + mode_ready="$credential_keychain_ready" + mode_hint_json=null + if [[ "$credential_login_ready" != "true" ]]; then + mode_hint_json='"Настройте логин и пароль: vpn --configure-login"' + elif [[ "$keychain_totp_seed" != "true" ]]; then + mode_hint_json='"Импортируйте код: vpn --import-yandex-key"' + fi + ;; + bitwarden-auto) + mode_label="Автоматически · Bitwarden" + auth_kind="auto" + auth_detail="Логин, пароль и код из Bitwarden; вход без ручного ввода" + mode_ready="$([[ "$bitwarden_installed" == "true" ]] && printf true || printf false)" + mode_hint_json="$([[ "$bitwarden_installed" == "true" ]] && printf null || printf '"Установите Bitwarden CLI или переустановите ручной режим"')" + ;; + *) + auth_kind="manual" + auth_detail="Обновите установку Lemana VPN" + mode_label="Неизвестный режим" + mode_ready=false + mode_hint_json='"Обновите Lemana VPN через install.sh"' + ;; + esac + + printf '{"core":{"openconnect":%s,"openconnect_lite":%s,"config":%s,"openconnect_lite_config":%s},"mode":{"id":"%s","label":"%s","ready":%s,"setup_hint":%s},"credentials":{"source":"%s","auth_profile":"%s","login_ready":%s,"keychain_ready":%s},"app_menu":%s,"bitwarden":{"enabled":%s,"installed":%s,"item":%s},"touchid":{"enabled":%s,"installed":%s},"keychain":{"password":%s,"totp_seed":%s},"dns_cleanup":{"installed":%s,"recovery_supported":%s,"stop_supported":%s},"patches":{"active":%s,"backup":%s},"app":{"installed":%s,"autostart":%s},"logging":{"max_bytes":%s},"local_otp":%s,"auth":{"mode":"%s","source":"%s","auto_source":"%s","label":"%s","detail":"%s","ready":%s,"setup_hint":%s}}' \ "$openconnect_installed" \ "$openconnect_lite_installed" \ "$config_present" \ "$oc_config_present" \ + "$MODE" \ + "$mode_label" \ + "$mode_ready" \ + "$mode_hint_json" \ "$CREDENTIAL_SOURCE" \ "$AUTH_PROFILE" \ "$credential_login_ready" \ @@ -387,16 +579,21 @@ _module_status_json() { "$app_menu_json" \ "$([[ "$USE_BITWARDEN" == "1" ]] && printf true || printf false)" \ "$bitwarden_installed" \ - "$BW_ITEM_NAME" \ + "$(printf '%s' "$BW_ITEM_NAME" | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))')" \ "$([[ "$USE_TOUCHID" == "1" ]] && printf true || printf false)" \ "$touchid_installed" \ "$keychain_password" \ "$keychain_totp_seed" \ "$dns_cleanup_installed" \ + "$(_module_bool _dns_recovery_supported)" \ + "$(_module_bool _session_stop_supported)" \ "$patches_active" \ "$patch_backup_present" \ "$app_installed" \ - "$app_autostart" + "$app_autostart" \ + "$LOG_MAX_BYTES" \ + "$([[ "$MODE" == "keychain-auto" ]] && printf true || printf false)" \ + "$auth_kind" "$CREDENTIAL_SOURCE" "$AUTO_SOURCE" "$mode_label" "$auth_detail" "$mode_ready" "$mode_hint_json" } _module_human_part() { @@ -428,7 +625,7 @@ _module_status_human() { app_installed="$(_module_bool test -x "$APP_DIR/Contents/MacOS/LemanaVPN")" app_autostart="$(_module_bool test -f "$LAUNCH_AGENT")" - printf 'Modules: %s %s, 🔐 auth_profile=%s, 🔐 credential_source=%s, ' "$([[ "$core" == "core=ok" ]] && printf '✅' || printf '⚠️')" "$core" "$AUTH_PROFILE" "$CREDENTIAL_SOURCE" + printf 'Modules: %s %s, 🔐 mode=%s, ' "$([[ "$core" == "core=ok" ]] && printf '✅' || printf '⚠️')" "$core" "$MODE" _module_human_part "bitwarden" "$USE_BITWARDEN" "$bitwarden_installed" printf ', ' _module_human_part "touchid" "$USE_TOUCHID" "$touchid_installed" @@ -441,9 +638,12 @@ _module_status_human() { "$([[ "$app_autostart" == "true" ]] && printf on || printf off)" \ "$([[ "$patches_active" == "true" ]] && printf '✅' || printf '⚠️')" \ "$([[ "$patches_active" == "true" ]] && printf active || printf pending)" \ - "$([[ "$AUTH_PROFILE" == "manual" || "$keychain_password" == "true" && "$AUTH_PROFILE" == "saved-login" || "$keychain_password" == "true" && "$keychain_totp_seed" == "true" ]] && printf '✅' || printf '⚠️')" \ + "$([[ "$keychain_password" == "true" && ( "$MODE" == "manual-keychain" && "$LOCAL_OTP" == "0" || "$keychain_totp_seed" == "true" ) ]] && printf '✅' || printf '⚠️')" \ "$([[ "$keychain_password" == "true" ]] && printf yes || printf no)" \ "$([[ "$keychain_totp_seed" == "true" ]] && printf yes || printf no)" + if [[ "$MODE" == "keychain-auto" ]]; then + printf 'Local OTP: %s\n' "$([[ "$keychain_totp_seed" == "true" ]] && printf ready || printf 'missing; run vpn --import-yandex-key')" + fi } _check_status() { @@ -460,12 +660,13 @@ _check_status() { return 0 fi - local status_json pid state ip expires dns_target + local status_json pid state ip expires started_at dns_target status_json="$(cat "$STATUS_FILE")" pid="$(printf '%s' "$status_json" | _json_get pid)" state="$(printf '%s' "$status_json" | _json_get state)" ip="$(printf '%s' "$status_json" | _json_get ip)" expires="$(printf '%s' "$status_json" | _json_get expires)" + started_at="$(printf '%s' "$status_json" | _json_get started_at)" dns_target="$(printf '%s' "$status_json" | _json_get dns_target)" local process_alive=false @@ -474,6 +675,11 @@ _check_status() { fi if [[ "$state" != "connected" ]] || ! $process_alive; then + if $process_alive && [[ "$state" == connecting || "$state" == reconnecting || "$state" == disconnecting ]]; then + if $JSON_MODE; then printf '{"state":"%s","pid":%s,"modules":%s}\n' "$state" "$pid" "$modules_json" + else printf 'VPN %s\n' "$state"; fi + return 0 + fi if $JSON_MODE; then printf '{"state":"disconnected","reason":"%s","modules":%s}\n' "$(! $process_alive && printf 'process dead (pid=%s)' "$pid" || printf '%s' "$state")" "$modules_json" else @@ -488,25 +694,27 @@ _check_status() { healthy=true fi - local remaining_sec=0 hours=0 mins=0 + local remaining_sec=0 hours=0 mins=0 session_label="срок неизвестен" if [[ -n "$expires" ]]; then local exp_ts now_ts - exp_ts="$(date -jf "%Y-%m-%dT%H:%M:%SZ" "$expires" "+%s" 2>/dev/null || true)" + exp_ts="$(date -u -jf "%Y-%m-%dT%H:%M:%SZ" "$expires" "+%s" 2>/dev/null || true)" now_ts="$(date "+%s")" if [[ -n "$exp_ts" ]]; then remaining_sec=$((exp_ts - now_ts)) + (( remaining_sec >= 0 )) || remaining_sec=0 hours=$((remaining_sec / 3600)) mins=$(((remaining_sec % 3600) / 60)) + session_label="${hours}h ${mins}m" fi fi if $JSON_MODE; then - printf '{"state":"connected","ip":"%s","healthy":%s,"remaining_sec":%s,"expires":"%s","pid":%s,"dns_target":"%s","modules":%s}\n' \ - "$ip" "$healthy" "$remaining_sec" "$expires" "$pid" "$dns_target" "$modules_json" + printf '{"state":"connected","ip":"%s","healthy":%s,"remaining_sec":%s,"expires":"%s","started_at":"%s","pid":%s,"dns_target":"%s","modules":%s}\n' \ + "$ip" "$healthy" "$remaining_sec" "$expires" "$started_at" "$pid" "$dns_target" "$modules_json" else _module_status_human - printf 'VPN connected - %s (session: %sh %sm, tunnel: %s)\n' \ - "$ip" "$hours" "$mins" "$($healthy && printf healthy || printf unhealthy)" + printf 'VPN connected - %s (session: %s, tunnel: %s)\n' \ + "$ip" "$session_label" "$($healthy && printf healthy || printf unhealthy)" fi } @@ -621,13 +829,39 @@ canonical_script = ''' regex_str = "^" + url_pattern.replace(".", var _afUrlPattern = new RegExp({js_regex_str}); var _afRun = 0; +var _afSubmitted = ""; +var _afRejectedOnce = false; +var _afFields = []; +var _afAttempt = {json.dumps(os.environ.get("LEMANA_VPN_AUTH_ATTEMPT", ""))}; +function _afRejected() {{ + if (!_afRejectedOnce) console.warn("LEMANA_VPN_AUTH_REJECTED"); + _afRejectedOnce = true; +}} +function _afMaySubmit() {{ + if (_afRejectedOnce || _afFields.length === 0) return false; + var stage = _afFields.includes("totp") ? "totp" : (_afFields.includes("password") ? "password" : "username"); + if (_afSubmitted === stage) return false; + try {{ + if (sessionStorage.getItem("lemana:" + _afAttempt + ":" + stage)) {{ + _afRejected(); return false; + }} + sessionStorage.setItem("lemana:" + _afAttempt + ":" + stage, "1"); + }} catch (e) {{ _afRejected(); return false; }} + _afSubmitted = stage; + return true; +}} function autoFill() {{ if (!_afUrlPattern.test(location.href.split('?')[0]) && !_afUrlPattern.test(location.href)) {{ _afRun++; return; }} _afRun++; - + if (_afRejectedOnce) return; + var error = document.querySelector("#input-error, #kc-error-message, .alert-error"); + if ({json.dumps(os.environ.get("LEMANA_VPN_AUTOFILL_CLICK", "1") != "0")} && error && error.getClientRects().length && error.textContent.trim()) {{ + _afRejected(); return; + }} + _afFields = []; {get_selectors(rules, credentials)} setTimeout(autoFill, 1000); }} @@ -652,6 +886,9 @@ elif old_script in src: else: fail("URL guard") +if "page = LemanaVPNPage(profile, self)" not in src: + replace_once("page = QWebEnginePage(profile, self)", "page = LemanaVPNPage(profile, self)", "terminal auth rejection", required=True) + selectors_marker = "def get_selectors(rules, credentials):\n" canonical_selectors = '''def get_selectors(rules, credentials): statements = [] @@ -667,7 +904,7 @@ canonical_selectors = '''def get_selectors(rules, credentials): value = json.dumps(getattr(credentials, rule.fill, None)) if value: statements.append( - f"""var elem = document.querySelector({selector}); if (elem) {{ elem.dispatchEvent(new Event("focus")); elem.value = {value}; elem.dispatchEvent(new Event("input", {{bubbles: true}})); elem.dispatchEvent(new Event("change", {{bubbles: true}})); elem.dispatchEvent(new Event("blur")); }}""" + f"""var elem = document.querySelector({selector}); if (elem && !elem.disabled && elem.type !== "hidden" && elem.getClientRects().length) {{ _afFields.push({json.dumps(rule.fill)}); elem.dispatchEvent(new Event("focus")); elem.value = {value}; elem.dispatchEvent(new Event("input", {{bubbles: true}})); elem.dispatchEvent(new Event("change", {{bubbles: true}})); elem.dispatchEvent(new Event("blur")); }}""" ) else: logger.warning( @@ -678,9 +915,18 @@ canonical_selectors = '''def get_selectors(rules, credentials): elif rule.action == "click": if os.environ.get("LEMANA_VPN_AUTOFILL_CLICK", "1") != "0": statements.append( - f"""var elem = document.querySelector({selector}); if (elem) {{ elem.dispatchEvent(new Event("focus")); elem.click(); }}""" + f"""var elem = document.querySelector({selector}); if (elem && _afMaySubmit()) {{ elem.dispatchEvent(new Event("focus")); elem.click(); }}""" ) return "\\n".join(statements) + + +class LemanaVPNPage(QWebEnginePage): + def javaScriptConsoleMessage(self, level, message, line, source): + if message == "LEMANA_VPN_AUTH_REJECTED" and os.environ.get("LEMANA_VPN_AUTOFILL_CLICK", "1") != "0": + logger.warning("LEMANA_VPN_AUTH_REJECTED") + QApplication.instance().exit(77) + return + super().javaScriptConsoleMessage(level, message, line, source) ''' if selectors_marker not in src: fail("auto-fill selectors") @@ -743,6 +989,10 @@ PY _store_keychain() { local password="$1" totp_secret="$2" + if [[ -z "${KC_USERNAME:-}" ]]; then + printf 'Cannot store VPN credentials: LDAP username is missing.\n' >&2 + return 1 + fi KC_USERNAME="$KC_USERNAME" _VPN_PASS="$password" _VPN_TOTP_SECRET="$totp_secret" "$OC_PYTHON" - <<'PY' import keyring import os @@ -786,27 +1036,36 @@ print(value) PY } +_tty_available() { + [[ -r /dev/tty && -w /dev/tty ]] || return 1 + { : <> /dev/tty; } 2>/dev/null +} + _can_prompt() { - [[ -r /dev/tty && -w /dev/tty ]] || [[ -t 0 ]] + _tty_available || [[ -t 0 ]] } _prompt_read() { - local var_name="$1" prompt="$2" secret="${3:-0}" value - if [[ -r /dev/tty && -w /dev/tty ]]; then + local var_name="$1" prompt="$2" secret="${3:-0}" value read_status=0 + if _tty_available; then if [[ "$secret" == "1" ]]; then - IFS= read -rsp "$prompt" value < /dev/tty || value="" + IFS= read -rsp "$prompt" value < /dev/tty || read_status=$? printf '\n' > /dev/tty else - IFS= read -rp "$prompt" value < /dev/tty || value="" + IFS= read -rp "$prompt" value < /dev/tty || read_status=$? fi else if [[ "$secret" == "1" ]]; then - IFS= read -rsp "$prompt" value || value="" + IFS= read -rsp "$prompt" value || read_status=$? printf '\n' else - IFS= read -rp "$prompt" value || value="" + IFS= read -rp "$prompt" value || read_status=$? fi fi + if (( read_status != 0 )); then + printf 'Input closed; credential setup cancelled.\n' >&2 + return 1 + fi printf -v "$var_name" '%s' "$value" } @@ -869,7 +1128,7 @@ _ensure_username() { fi while [[ -z "${KC_USERNAME:-}" ]]; do - _prompt_read KC_USERNAME "Corporate LDAP username: " + _prompt_read KC_USERNAME "Corporate LDAP username: " || return 1 KC_USERNAME="${KC_USERNAME#"${KC_USERNAME%%[![:space:]]*}"}" KC_USERNAME="${KC_USERNAME%"${KC_USERNAME##*[![:space:]]}"}" if [[ -z "$KC_USERNAME" ]]; then @@ -895,14 +1154,14 @@ _configure_keychain() { printf 'Saved values go to macOS Keychain service openconnect-lite.\n\n' if $password_present; then - _prompt_read password "Corporate LDAP password for $KC_USERNAME [leave empty to keep saved password]: " 1 + _prompt_read password "Corporate LDAP password for $KC_USERNAME [leave empty to keep saved password]: " 1 || return 1 else - _prompt_read password "Corporate LDAP password for $KC_USERNAME: " 1 + _prompt_read password "Corporate LDAP password for $KC_USERNAME: " 1 || return 1 fi if $totp_present; then - _prompt_read totp_secret "2FA setup secret BASE32 [leave empty to keep saved secret]: " 1 + _prompt_read totp_secret "2FA setup secret BASE32 [leave empty to keep saved secret]: " 1 || return 1 else - _prompt_read totp_secret "2FA setup secret BASE32: " 1 + _prompt_read totp_secret "2FA setup secret BASE32: " 1 || return 1 fi if [[ -z "$password" && "$password_present" != "true" ]]; then @@ -930,12 +1189,16 @@ _configure_login() { printf 'User: %s\n' "$KC_USERNAME" printf 'LDAP password: your corporate LDAP/domain password, not the Bitwarden master password.\n' printf 'Saved values go to macOS Keychain service openconnect-lite.\n' - printf 'One-time 2FA codes will still be entered manually during VPN login.\n\n' + if [[ "$LOCAL_OTP" == "1" ]]; then + printf 'One-time codes use the separately imported Keychain secret.\n\n' + else + printf 'One-time 2FA codes will still be entered manually during VPN login.\n\n' + fi if $password_present; then - _prompt_read password "Corporate LDAP password for $KC_USERNAME [leave empty to keep saved password]: " 1 + _prompt_read password "Corporate LDAP password for $KC_USERNAME [leave empty to keep saved password]: " 1 || return 1 else - _prompt_read password "Corporate LDAP password for $KC_USERNAME: " 1 + _prompt_read password "Corporate LDAP password for $KC_USERNAME: " 1 || return 1 fi if [[ -z "$password" && "$password_present" != "true" ]]; then @@ -985,19 +1248,41 @@ _ensure_keychain_credentials() { if [[ "$CREDENTIAL_SOURCE" == "bitwarden" ]]; then _emit '{"event":"keychain_required","source":"bitwarden"}' "Bitwarden source did not produce complete Keychain credentials." + _emit '{"event":"error","message":"Bitwarden did not provide complete LDAP username/password/TOTP. Check bw login and the LM LDAP item."}' \ + "Bitwarden did not provide complete LDAP username/password/TOTP. Check: bw login and item '$BW_ITEM_NAME'." + return 1 else _emit '{"event":"keychain_required","source":"keychain"}' "Keychain source is selected and saved LDAP credentials are incomplete." fi if ! _can_prompt; then - _emit '{"event":"error","message":"Automatic sign-in is not configured. Run vpn --configure-keychain in Terminal, or use vpn --manual-full."}' \ - "Automatic sign-in is not configured. Run: vpn --configure-keychain" + _emit '{"event":"error","message":"Bitwarden automatic sign-in is not configured. Check bw login/LM LDAP, or switch to manual-keychain."}' \ + "Bitwarden automatic sign-in is not configured. Check bw login/LM LDAP, or switch to manual-keychain." return 1 fi _configure_keychain } +_import_yandex_key() { + if ! _can_prompt; then + printf 'Импорт требует Terminal. Запустите: vpn --import-yandex-key\n' >&2 + return 1 + fi + if [[ -z "$KC_USERNAME" ]] || ! _keychain_has openconnect-lite "$KC_USERNAME"; then + printf 'Сначала настройте логин и пароль: vpn --configure-login\n' >&2 + return 1 + fi + local helper saved_username + saved_username="$(unset LEMANA_VPN_USERNAME; source "$CONFIG_FILE"; printf '%s' "${LEMANA_VPN_USERNAME:-}")" + if [[ "$saved_username" != "$KC_USERNAME" ]]; then + printf 'LDAP username отличается от сохранённой настройки. Запустите vpn --configure-login без переопределения username.\n' >&2 + return 1 + fi + helper="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/lemana-vpn-import-yandex.py" + XDG_CONFIG_HOME="$OC_RUNTIME_XDG_CONFIG_HOME" "$OC_PYTHON" "$helper" "--username=$KC_USERNAME" --config "$CONFIG_FILE" +} + _bw_cache_session() { [[ "$CACHE_BW_SESSION" == "1" ]] || return 0 local session="$1" @@ -1045,7 +1330,7 @@ _bw_unlock() { fi _emit '{"event":"bw_manual"}' "Bitwarden vault is locked. Enter Bitwarden master password to sync LDAP credentials." - _prompt_read manual_pw "Bitwarden master password (not LDAP password): " 1 + _prompt_read manual_pw "Bitwarden master password (not LDAP password): " 1 || return 1 if [[ -z "$manual_pw" ]]; then printf 'Empty Bitwarden password. Using existing Keychain credentials.\n' >&2 return 1 @@ -1061,7 +1346,7 @@ _bw_unlock() { if [[ "$USE_TOUCHID" == "1" && -x "$KC_FP" ]]; then local save_choice - _prompt_read save_choice "Save Bitwarden master password behind Touch ID for next VPN unlock? [Y/n] " + _prompt_read save_choice "Save Bitwarden master password behind Touch ID for next VPN unlock? [Y/n] " || { unset manual_pw; return 1; } if [[ "${save_choice:-y}" =~ ^[Yy]?$ ]]; then printf '%s' "$manual_pw" | "$KC_FP" set "$BW_KC_SERVICE" "$BW_KC_ACCOUNT_MASTER" >/dev/null 2>&1 \ && printf 'Saved. Next unlock can use Touch ID.\n' \ @@ -1078,9 +1363,19 @@ _sync_bitwarden() { return 0 fi - local bw_password bw_item bw_totp_secret + local bw_password bw_item bw_username bw_totp_secret bw_password="$(bw get password "$BW_ITEM_NAME" --session "$BW_SESSION" 2>/dev/null || true)" bw_item="$(bw get item "$BW_ITEM_NAME" --session "$BW_SESSION" 2>/dev/null || true)" + bw_username="$(printf '%s' "$bw_item" | python3 -c ' +import json +import sys + +try: + data = json.load(sys.stdin) + print((data.get("login", {}).get("username", "") or "").strip()) +except Exception: + print("") +')" bw_totp_secret="$(printf '%s' "$bw_item" | python3 -c ' import json import re @@ -1098,7 +1393,18 @@ except Exception: print("") ')" + if [[ -n "$bw_username" && "$bw_username" != "${KC_USERNAME:-}" ]]; then + KC_USERNAME="$bw_username" + export LEMANA_VPN_USERNAME="$KC_USERNAME" + _persist_username + _emit '{"event":"username_saved","source":"bitwarden"}' "LDAP username synced from Bitwarden." + fi + if [[ -n "$bw_password" ]]; then + if [[ -z "${KC_USERNAME:-}" ]]; then + printf 'Could not fetch LDAP username from Bitwarden item "%s". Using existing Keychain credentials.\n' "$BW_ITEM_NAME" >&2 + return 0 + fi if [[ -n "$bw_totp_secret" ]]; then bw_totp_secret="$(_normalize_totp_secret "$bw_totp_secret")" fi @@ -1125,79 +1431,247 @@ _sync_credentials() { _dns_cleanup() { _emit '{"event":"dns_cleanup"}' "Cleaning up VPN DNS..." - if [[ -x "$DNS_CLEANUP" ]]; then - sudo "$DNS_CLEANUP" || true - return 0 + if _dns_recovery_supported; then + # Replace the finished CLI so the process guard sees that this session ended. + # Keep the client's exit code; DNS recovery must not change reconnect policy. + # OpenConnect and its disconnect hook can outlive openconnect-lite on SIGINT. + exec /bin/sh -c ' + result=active + attempt=0 + while [ "$attempt" -lt 30 ]; do + attempt=$((attempt + 1)) + if ! result=$(sudo -n "$1" --recover); then result=error; break; fi + case "$result" in + restored|unchanged|no_snapshot) break ;; + active) [ "$attempt" -ge 30 ] || sleep 1 ;; + *) result=error; break ;; + esac + done + if [ "$3" = true ]; then + printf "{\"event\":\"dns_recovery\",\"result\":\"%s\"}\n" "$result" + fi + case "$result" in + error) printf "DNS recovery failed; retry vpn --repair-dns.\n" >&2 ;; + active) printf "VPN processes are still active; DNS recovery deferred. Retry vpn --repair-dns after they exit.\n" >&2 ;; + esac + exit "$2" + ' dns-recovery "$DNS_CLEANUP" "$1" "$JSON_MODE" fi +} - for svc in "Wi-Fi" "USB 10/100/1000 LAN" "Ethernet"; do - local dns - dns="$(networksetup -getdnsservers "$svc" 2>/dev/null || true)" - if printf '%s\n' "$dns" | grep -q '^10\.'; then - sudo networksetup -setdnsservers "$svc" empty >/dev/null 2>&1 || true +_repair_dns() { + local result=error message="Не удалось восстановить DNS. Обновите установку: sh install.sh" code=1 + if _dns_recovery_supported; then + if result="$(sudo -n "$DNS_CLEANUP" --recover)"; then + case "$result" in + restored) message="Прежние настройки DNS восстановлены"; code=0 ;; + unchanged) message="Восстановление DNS не требуется"; code=0 ;; + no_snapshot) message="Сохранённых изменений VPN DNS нет"; code=0 ;; + active) message="VPN уже запущен; DNS оставлен без изменений"; code=0 ;; + *) result=error ;; + esac + else + result=error + message="Не удалось проверить DNS. Обновите установку: sh install.sh; затем повторите vpn --repair-dns" fi + fi + _emit "{\"event\":\"dns_recovery\",\"result\":\"$result\",\"message\":\"$message\"}" "$message" + return "$code" +} + +_parse_expiry() { + python3 - "$1" <<'PYDATE' +import datetime as dt +import locale +import re +import sys +locale.setlocale(locale.LC_TIME, 'C') +raw = ' '.join(sys.argv[1].split()) +zone = None +numeric = re.search(r' ([+-])(\d{2})(?::?(\d{2}))?$', raw) +if numeric: + hours, minutes = int(numeric[2]), int(numeric[3] or 0) + if hours > 14 or minutes > 59: + sys.exit(1) + zone = dt.timezone(dt.timedelta(minutes=(hours * 60 + minutes) * (-1 if numeric[1] == '-' else 1))) + raw = raw[:numeric.start()] +elif re.search(r' [A-Za-z]+$', raw): + # OpenConnect renders named zones from this machine's local time. + raw = raw.rsplit(' ', 1)[0] +for pattern in ('%a, %d %b %Y %H:%M:%S', '%a %b %d %H:%M:%S %Y'): + try: + value = dt.datetime.strptime(raw, pattern) + if zone is not None: + value = value.replace(tzinfo=zone) + print(int(value.timestamp())) + break + except ValueError: + pass +else: + sys.exit(1) +PYDATE +} + +_valid_ipv4() { + local octet + local IFS=. + for octet in $1; do + [[ "$octet" =~ ^[0-9]{1,3}$ ]] && ((10#$octet <= 255)) || return 1 done - sudo dscacheutil -flushcache >/dev/null 2>&1 || true - sudo killall -HUP mDNSResponder >/dev/null 2>&1 || true +} + +_publish_connection() { + local remaining=0 dns_target + if [[ -n "$expiry_ts" ]]; then + remaining=$((expiry_ts - $(date +%s))) + (( remaining >= 0 )) || remaining=0 + fi + _emit "{\"event\":\"$1\",\"ip\":\"$vpn_ip\",\"expires\":\"$expiry_iso\",\"started_at\":\"$session_started_at\",\"remaining_sec\":$remaining,\"attempt_id\":\"${auth_attempt:-}\"}" "VPN connected - $vpn_ip" + dns_target="$(scutil --dns 2>/dev/null | awk '/Supplemental/{found=1} found && /nameserver\[0\]/{split($0,a," : "); if(a[2] ~ /^10\./) {print a[2]; exit}}' || true)" + _write_status "{\"pid\":$$,\"state\":\"connected\",\"ip\":\"$vpn_ip\",\"expires\":\"$expiry_iso\",\"started_at\":\"$session_started_at\",\"dns_target\":\"$dns_target\",\"updated_at\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"}" } _filter_output() { - local vpn_ip="" + local vpn_ip="" session_started_at="" expiry_iso="" expiry_ts="" parsed_ts="" + local connected=false rejected=false while IFS= read -r line; do _log_connection_line "$line" - if $DEBUG; then printf '%s\n' "$line" elif ! $JSON_MODE; then case "$line" in *ERROR*|*Error*|*error*|*Failed*|*failed*|*Traceback*|*SAML*|*saml*|*Keycloak*|*keycloak*|*Cisco*|*auth*|*Auth*) - printf '[openconnect-lite] %s\n' "$line" - ;; + printf '[openconnect-lite] %s\n' "$line" ;; esac fi - - if [[ "$line" =~ Configured\ as\ ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+) ]]; then - vpn_ip="${BASH_REMATCH[1]}" + if [[ "$line" == *LEMANA_VPN_AUTH_REJECTED* ]] && [[ "${MODE:-manual-keychain}" != manual-keychain ]] && ! $connected && ! $rejected; then + rejected=true + [[ -z "${ATTEMPT_DIR:-}" ]] || : > "$ATTEMPT_DIR/auth-rejected" + _emit '{"event":"auth_rejected","message":"Автоматический вход остановлен: форма отклонила или повторно запросила данные. Проверьте пароль и одноразовый код."}' 'Автоматический вход остановлен. Проверьте пароль и одноразовый код.' fi - - if [[ "$line" =~ Session\ authentication\ will\ expire\ at\ (.+) ]]; then - _stop_connect_progress - local expiry_str="${BASH_REMATCH[1]}" - local expiry_ts expiry_local expiry_iso now_ts remaining hours mins - expiry_ts="$(date -jf "%a %b %d %H:%M:%S %Y" "$expiry_str" "+%s" 2>/dev/null || true)" - expiry_iso="" - if [[ -n "$expiry_ts" ]]; then - expiry_local="$(date -jf "%a %b %d %H:%M:%S %Y" "$expiry_str" "+%H:%M" 2>/dev/null || true)" - expiry_iso="$(date -r "$expiry_ts" -u "+%Y-%m-%dT%H:%M:%SZ" 2>/dev/null || true)" - now_ts="$(date "+%s")" - remaining=$((expiry_ts - now_ts)) - hours=$((remaining / 3600)) - mins=$(((remaining % 3600) / 60)) + $rejected && continue + if [[ "$line" =~ Configured\ as\ ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)($|[[:space:],]) ]] && _valid_ipv4 "${BASH_REMATCH[1]}"; then + # _valid_ipv4 also uses regex matching, so capture the IP independently. + vpn_ip="${line#*Configured as }"; vpn_ip="${vpn_ip%%[!0-9.]*}" + if ! $connected; then + connected=true + session_started_at="$(date -u +%Y-%m-%dT%H:%M:%SZ)" + [[ -z "${ATTEMPT_DIR:-}" ]] || : > "$ATTEMPT_DIR/connected" + _stop_connect_progress + _publish_connection connected fi - - if [[ -n "$vpn_ip" ]]; then - _emit "{\"event\":\"connected\",\"ip\":\"$vpn_ip\",\"expires\":\"$expiry_iso\"}" "VPN connected - $vpn_ip" - else - _emit '{"event":"connected"}' "VPN connected" + elif [[ "$line" == *'Session authentication will expire at '* ]]; then + if parsed_ts="$(_parse_expiry "${line#*Session authentication will expire at }")"; then + expiry_ts=$parsed_ts + expiry_iso="$(date -u -r "$expiry_ts" +%Y-%m-%dT%H:%M:%SZ)" + if $connected; then _publish_connection session_info; fi fi - if [[ -n "${expiry_ts:-}" ]]; then - _emit "{\"event\":\"session_info\",\"ip\":\"${vpn_ip:-}\",\"expires\":\"$expiry_iso\",\"remaining_sec\":$remaining}" "Session until $expiry_local (${hours}h ${mins}m)" - fi - - local dns_target - dns_target="$(scutil --dns 2>/dev/null | awk '/Supplemental/{found=1} found && /nameserver\[0\]/{split($0,a," : "); if(a[2] ~ /^10\./) {print a[2]; exit}}' || true)" - _write_status "{\"pid\":$$,\"state\":\"connected\",\"ip\":\"${vpn_ip:-}\",\"expires\":\"${expiry_iso:-}\",\"started_at\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"dns_target\":\"${dns_target:-}\",\"updated_at\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"}" - - $DEBUG || $JSON_MODE || printf '%s\n' "Ctrl+C to disconnect" fi done } +_recover_for_retry() { + local result=active attempt + for ((attempt=1; attempt<=30; attempt++)); do + if ! result="$(sudo -n "$DNS_CLEANUP" --recover-session "$SESSION_ID")"; then return 1; fi + case "$result" in + restored|unchanged|no_snapshot) return 0 ;; + cancelled) return 2 ;; + active) (( attempt >= 30 )) || sleep 1 ;; + *) return 1 ;; + esac + done + return 1 +} + +_run_connections() { + local failures=0 delay=0 exit_code recovery_code auth_attempt + local -a pipeline_status + while true; do + rm -f "$ATTEMPT_DIR/connected" "$ATTEMPT_DIR/auth-rejected" + auth_attempt="$(uuidgen | tr '[:upper:]' '[:lower:]')" + _emit '{"event":"connecting"}' 'Connecting to VPN (lemanapro)...' + _write_status "{\"pid\":$$,\"state\":\"connecting\"}" + _start_connect_progress + set +e + QTWEBENGINE_CHROMIUM_FLAGS="--disable-gpu" \ + XDG_CONFIG_HOME="$OC_RUNTIME_XDG_CONFIG_HOME" \ + LEMANA_VPN_AUTH_ATTEMPT="$auth_attempt" \ + LEMANA_VPN_AUTOFILL_DEBUG="$autofill_debug" \ + LEMANA_VPN_AUTOFILL_DISABLE="$autofill_disable" \ + LEMANA_VPN_AUTOFILL_CLICK="$autofill_click" \ + LEMANA_VPN_AUTOFILL_TOTP="$autofill_totp" \ + "$OC_BIN" --browser-display-mode "$display_mode" $log_level -- --script "$dns_hook $auth_attempt" 2>&1 | _filter_output + pipeline_status=("${PIPESTATUS[@]}") + set -e + exit_code=${pipeline_status[0]} + _stop_connect_progress + if [[ -f "$ATTEMPT_DIR/auth-rejected" ]]; then return 77; fi + if [[ "${pipeline_status[1]}" != 0 ]]; then + _emit '{"event":"error","message":"Не удалось прочитать состояние VPN. Автоматический повтор остановлен."}' 'VPN output processing failed.' + return 1 + fi + if [[ "$MODE" == manual-keychain ]] || { [[ ! -f "$ATTEMPT_DIR/connected" ]] && [[ "$exit_code" == 2 || "$exit_code" == 130 || "$exit_code" == 143 ]]; }; then + _emit '{"event":"disconnected","reason":"ended"}' 'VPN disconnected' + return "$exit_code" + fi + _emit '{"event":"reconnecting","attempt":1,"delay":0}' 'Проверяю завершение туннеля и DNS перед повтором…' + _write_status "{\"pid\":$$,\"state\":\"reconnecting\"}" + recovery_code=0 + _recover_for_retry || recovery_code=$? + case "$recovery_code" in + 2) _emit '{"event":"disconnected","reason":"user"}' 'VPN disconnected'; return 0 ;; + 0) ;; + *) _emit '{"event":"error","message":"Повторное подключение остановлено: предыдущий туннель или DNS ещё не восстановлены."}' 'VPN/DNS recovery incomplete; reconnect stopped.'; return 1 ;; + esac + if [[ -f "$ATTEMPT_DIR/connected" ]]; then + failures=0; delay=5 + else + if (( failures >= 5 )); then + _emit '{"event":"error","message":"Не удалось подключиться после пяти повторов. Проверьте сеть и настройки входа."}' 'Reconnect limit reached.' + return 1 + fi + delay=$((5 << failures)); (( delay <= 60 )) || delay=60 + failures=$((failures + 1)) + fi + _emit "{\"event\":\"reconnecting\",\"attempt\":$((failures > 0 ? failures : 1)),\"delay\":$delay}" "Повторное подключение через $delay с…" + sleep "$delay" + done +} + +if [[ -n "$RESTART_SESSION" ]]; then + _session_stop_supported && grep -qx '# LEMANA_RECONNECT_PROTOCOL=1' "$DNS_CLEANUP" || exit 1 + [[ -n "$RESTART_ATTEMPT" ]] || exit 2 + restart_result="$(sudo -n "$DNS_CLEANUP" --restart "$RESTART_SESSION" "$RESTART_ATTEMPT")" + case "$restart_result" in stopping|stale|cancelled) printf '%s\n' "$restart_result" ;; *) exit 1 ;; esac + exit 0 +fi + +if [[ -n "$STOP_SESSION" ]]; then + _stop_session + exit 0 +fi + +if $REPAIR_DNS_MODE; then + _repair_dns + exit 0 +fi + +if [[ -n "$SET_AUTH" ]]; then + _set_auth + exit 0 +fi + if $STATUS_MODE; then _check_status exit 0 fi +if $IMPORT_YANDEX_KEY_MODE; then + _import_yandex_key + exit 0 +fi + if $CONFIGURE_LOGIN_MODE; then _ensure_username _configure_login @@ -1215,35 +1689,59 @@ if $PATCH_ONLY_MODE; then exit 0 fi +if [[ "$MODE" == keychain-auto ]]; then + if [[ -z "$KC_USERNAME" ]] || ! _keychain_has openconnect-lite "$KC_USERNAME"; then + _emit '{"event":"error","message":"Настройте логин и пароль: vpn --configure-login"}' "Настройте логин и пароль: vpn --configure-login" + exit 1 + fi + if ! _keychain_has openconnect-lite "totp/$KC_USERNAME"; then + _emit '{"event":"error","message":"Импортируйте код: vpn --import-yandex-key"}' "Импортируйте код: vpn --import-yandex-key" + exit 1 + fi +fi + +if ! _dns_recovery_supported || ! _session_stop_supported || ! grep -qx '# LEMANA_RECONNECT_PROTOCOL=1' "$DNS_CLEANUP"; then + _emit '{"event":"error","message":"Обновите helper перед подключением: sh install.sh"}' "Обновите helper перед подключением: sh install.sh" + exit 1 +fi +[[ -n "$SESSION_ID" ]] || SESSION_ID="$(uuidgen | tr '[:upper:]' '[:lower:]')" +session_sudo=() +if $JSON_MODE || [[ ! -t 0 ]]; then session_sudo=(-n); fi +if [[ ! "$SESSION_ID" =~ ^[a-f0-9-]{36}$ ]] || ! begin_result="$(sudo "${session_sudo[@]}" "$DNS_CLEANUP" --begin "$SESSION_ID" "$$")" || [[ "$begin_result" != ready ]]; then + _emit '{"event":"error","message":"Не удалось зарегистрировать VPN-сессию. Проверьте установку и текущий статус."}' "Не удалось зарегистрировать VPN-сессию." + exit 1 +fi +ATTEMPT_DIR="$(mktemp -d "${TMPDIR:-/tmp}/lemana-vpn-attempt.XXXXXX")" +trap 'trap_exit_code=$?; rm -rf "$ATTEMPT_DIR"; _stop_connect_progress; _cleanup_manual_openconnect_config || true; _clear_status || true; _dns_cleanup "$trap_exit_code"' EXIT +trap 'exit 143' TERM +_emit '{"event":"session_ready"}' "VPN session registered" + if ! $JSON_MODE; then _module_status_human else printf '{"event":"modules","modules":%s}\n' "$(_module_status_json)" fi -case "$AUTH_PROFILE" in - manual) - _emit '{"event":"auth_profile","profile":"manual","message":"Manual mode skips saved credential checks"}' \ - "Manual mode: open the visible browser and enter login, password, and one-time code manually." +case "$MODE" in + manual-keychain) + if $FULL_MANUAL_OVERRIDE; then + _emit '{"event":"mode","id":"manual-keychain","diagnostic":true,"message":"Diagnostic manual fallback skips saved credential checks"}' \ + "Diagnostic manual fallback: open the visible browser without auto-fill." + else + _ensure_username + _sync_credentials + _ensure_keychain_login + fi ;; - saved-login) - _ensure_username - _sync_credentials - _ensure_keychain_login - ;; - saved-totp|auto) - _ensure_username + bitwarden-auto) _sync_credentials _ensure_keychain_credentials ;; esac _patch_oc -_emit '{"event":"connecting"}' "Connecting to VPN (lemanapro)..." -_write_status "{\"pid\":$$,\"state\":\"connecting\",\"updated_at\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"}" _prepare_connection_log _emit '{"event":"log","message":"openconnect-lite log is enabled"}' "openconnect-lite log: $CONNECT_LOG_FILE" -trap '_stop_connect_progress; _dns_cleanup; _cleanup_manual_openconnect_config; _clear_status' EXIT display_mode="shown" log_level="" @@ -1251,32 +1749,25 @@ autofill_debug="${LEMANA_VPN_AUTOFILL_DEBUG:-0}" autofill_disable="${LEMANA_VPN_AUTOFILL_DISABLE:-1}" autofill_click="${LEMANA_VPN_AUTOFILL_CLICK:-0}" autofill_totp="${LEMANA_VPN_AUTOFILL_TOTP:-0}" -case "$AUTH_PROFILE" in - manual) +case "$MODE" in + manual-keychain) autofill_disable="1" autofill_click="0" autofill_totp="0" - _prepare_manual_openconnect_config - _emit '{"event":"manual_sso","auth_profile":"manual","autofill":false,"submit":false}' "Manual mode: browser is visible, auto-fill is disabled, submit is not pressed." + if $FULL_MANUAL_OVERRIDE; then + _prepare_manual_openconnect_config + _emit '{"event":"manual_sso","mode":"manual-keychain","diagnostic":true,"autofill":false,"totp":false,"submit":false}' "Manual fallback: browser is visible, auto-fill is disabled, submit is not pressed." + else + autofill_disable="0" + _emit '{"event":"manual_sso","mode":"manual-keychain","autofill":true,"totp":false,"submit":false}' "Manual mode: browser is visible, login/password are filled, one-time code and submit are manual." + fi ;; - saved-login) - autofill_disable="0" - autofill_click="0" - autofill_totp="0" - _emit '{"event":"manual_sso","auth_profile":"saved-login","autofill":true,"totp":false,"submit":false}' "Saved-login mode: browser is visible, login/password are filled, one-time code is manual." - ;; - saved-totp) - autofill_disable="0" - autofill_click="0" - autofill_totp="1" - _emit '{"event":"manual_sso","auth_profile":"saved-totp","autofill":true,"totp":true,"submit":false}' "Saved-TOTP mode: browser is visible, saved fields are filled, submit is not pressed." - ;; - auto) + keychain-auto|bitwarden-auto) display_mode="hidden" autofill_disable="0" autofill_click="1" autofill_totp="1" - _emit '{"event":"auto_sso","auth_profile":"auto","autofill":true,"submit":true}' "Auto mode: hidden browser, auto-fill and auto-submit." + _emit "{\"event\":\"auto_sso\",\"mode\":\"$MODE\",\"autofill\":true,\"totp\":true,\"submit\":true}" "Automatic mode: hidden browser, auto-fill and auto-submit." ;; esac if $DEBUG; then @@ -1285,28 +1776,6 @@ if $DEBUG; then autofill_debug="1" fi -reconnect_count=0 -while true; do - _start_connect_progress - QTWEBENGINE_CHROMIUM_FLAGS="--disable-gpu" \ - XDG_CONFIG_HOME="$OC_RUNTIME_XDG_CONFIG_HOME" \ - LEMANA_VPN_AUTOFILL_DEBUG="$autofill_debug" \ - LEMANA_VPN_AUTOFILL_DISABLE="$autofill_disable" \ - LEMANA_VPN_AUTOFILL_CLICK="$autofill_click" \ - LEMANA_VPN_AUTOFILL_TOTP="$autofill_totp" \ - "$OC_BIN" --browser-display-mode "$display_mode" $log_level 2>&1 \ - | _filter_output - exit_code=${PIPESTATUS[0]} - _stop_connect_progress - - if [[ $exit_code -eq 0 ]]; then - _emit '{"event":"disconnected","reason":"user"}' "VPN disconnected" - break - fi - - _show_connection_log_tail - reconnect_count=$((reconnect_count + 1)) - _emit "{\"event\":\"reconnecting\",\"attempt\":$reconnect_count,\"delay\":5}" "VPN exited with $exit_code. Reconnecting in 5s..." - sleep 5 - _emit '{"event":"connecting"}' "Reconnecting..." -done +# openconnect executes --script through a shell; quote the configured path as data. +dns_hook="$(python3 -c 'import shlex,sys; print(shlex.quote(sys.argv[1]) + " --vpnc " + shlex.quote(sys.argv[2]))' "$DNS_CLEANUP" "$SESSION_ID")" +_run_connections diff --git a/docs/goals/compact-menu/GOAL.md b/docs/goals/compact-menu/GOAL.md new file mode 100644 index 0000000..563d5b6 --- /dev/null +++ b/docs/goals/compact-menu/GOAL.md @@ -0,0 +1,3 @@ +# Goal: Compact Lemana VPN menu + +Execute `docs/goals/compact-menu/PLAN.md` with Krypton Execution. Implement the approved mock while preserving all existing auth and connection actions. Use real CLI timestamps, retain older-CLI fallback, keep credentials in the CLI, and report that native visual/live acceptance is untested. Preserve all prior dirty changes. diff --git a/docs/goals/compact-menu/PLAN.md b/docs/goals/compact-menu/PLAN.md new file mode 100644 index 0000000..0acd421 --- /dev/null +++ b/docs/goals/compact-menu/PLAN.md @@ -0,0 +1,41 @@ +# Compact Menu and Session Indicator Implementation Plan + +**Intent:** Implement the approved compact macOS menu mockup with Yandex Key import and a small configurable session indicator. +**Current Behavior:** MenuBarExtra uses a plain menu, shield plus H:MM, dense module diagnostics and a login Terminal action. CLI stores started_at but does not expose it to events/status and resets it on repeated expiry lines. +**Expected Outcome:** A native 298-point popover matching the approved layout; import/login actions, preserved connection actions, a persisted ring/clock/time preference (16-point ring default), exact remaining time in menu, elapsed fill and green/amber/red urgency. +**Target-Perspective Output:** Synthetic CLI transcript produces stable started_at plus real expiry; compiled presentation checks demonstrate progress/time/color boundaries, reset/legacy handling and correctly quoted Terminal commands. Release app compiles. Native visual acceptance remains explicitly untested because no GUI testing was requested. +**Truth Owner:** CLI owns connection start/expiry metadata; Swift session model computes derived presentation. UserDefaults owns the indicator preference. CLI/Keychain still own import and credentials. +**Contract Boundary:** Add optional started_at to existing events and connected status; preserve all old fields and auth modes. Swift falls back to the first observed connection time with older CLI, never to an assumed duration. +**Cutover:** Replace the existing plain menu and shield+time connected presentation in place with the approved popover and selected indicator. Reuse the Terminal launcher for import; no second credential UI. +**Displaced Path:** Unconditional shield+time becomes a selected style; dense healthy module details leave the default surface, actionable setup/tunnel warnings remain visible. No new VPN connection/reconnect logic. +**Value Density:** Native SwiftUI window menu, AppStorage and AppKit image drawing; no dependencies, app installation or platform rewrite. +**Acceptance Evidence:** Automated event/status transcript, pure Foundation session checks, generated Zsh script execution against a fake CLI, existing regression suites and Swift build. +**Evidence Lane:** Automated only. No app/Terminal launch, GUI, screenshot, live VPN, real Keychain or installation. +**Kill Criteria:** No fixed 8h duration, repeated timing events cannot reset fill, disabled/disconnected states cannot show stale time, imported secret never enters Swift, new sources ship in installer, existing auth/cancel/copy/log/quit actions remain reachable. +**Architecture Slice:** `bin/vpn-lemanapro.sh` -> VPNEvent -> `VPNManager.swift` -> new Foundation `SessionTiming.swift` -> `LemanaVPNApp.swift`; installer explicitly downloads the new source; focused tests and README describe behavior. Existing dirty work is preserved. +**Plan Review Gate:** Requires PRE review before execution. + +## Tasks + +1. Root: persist one start timestamp per `_filter_output` connection, include it in connected/session_info/status output, test repeated expiry lines and status round-trip with fake tools. No SSO/DNS/reconnect changes. +2. Root: add session timing model, optional event timestamp, reset on lifecycle transitions, update presentation once per second, preserve legacy timestamp fallback; fix JSON line buffering if required to deliver the new contract through real pipe chunks. Test timing independently and via decoded event fixtures. +3. Root: approved native popover, 16px ring/clock and compact time option, persisted preference, localized accessible status, visible setup/tunnel failures, all existing actions. Reuse Terminal script builder for import and login, fixing the existing read-only Zsh `status` variable and using per-action success text; setup launch failure must not replace an active VPN state. +4. Root: update source packaging, README and narrow smoke wiring expectations; run automated checks and POST correctness/maintainability review. Review agents are read-only; implementation stays with root. + +## Behavior details + +- Fill = clamp((now - started_at) / (expires - started_at), 0...1) for valid positive duration. Unknown/invalid expiry uses a normal connection symbol and “Срок сессии неизвестен”. +- Remaining >60min green; <=60min amber; <=15min red, including expiry. Exact menu text and accessibility labels accompany color. No continuous decorative spinner. +- Expiry alone does not start another session or pretend the process ended; keep disconnect while the process is still connected. Disconnected/reconnecting/error use distinct system symbols and no stale countdown. +- Start/end reset on an actual new connection attempt and terminal states; repeated connected/session_info data in one attempt retains its origin. RefreshStatus remains a module refresh, without attaching to external VPN processes. +- Approved reference: `/Users/dokril/.codex/visualizations/2026/10/07/01a117e8-cae9-7f02-9dc7-c177c368a223/vpn-menu.html`. Mock-specific demonstration controls are not shipped. + +## Completed implementation and evidence + +- Native `.window` menu, 298 pt layout, AppStorage ring/clock/time preference, 16 pt AppKit ring/clock image, exact remaining-time labels, import/login Terminal actions and all connection/cancel/copy/log/quit paths implemented. Healthy raw module summaries removed; actionable failures remain visible. +- CLI event, status file and status response share a stable start timestamp. Foundation timing logic handles observed legacy starts, real duration, clamping, unknown/invalid intervals and 60/15-minute thresholds. Lifecycle transitions reset timing, and the UI updates once per second. +- `tests/menu.py`: PASS. Real shell filter/status transcript with synthetic dates, repeated expiry and reconnect; compiled Swift model, every byte boundary in UTF-8/JSON framing, old CLI sole manual-full action; generated Terminal scripts executed in Zsh against a fake quoted-path CLI for success and exit 7. No Terminal application launched. +- `tests/smoke.sh`, `tests/logging.py`, `tests/configuration.py` (10 checks), `tests/yandex_import.py`, shell syntax and `git diff --check`: PASS. +- Final `swift build -c release --package-path app`: PASS (3.07 s). One restricted attempt was blocked by the compiler cache sandbox; an approved build escalation succeeded. +- PRE and POST correctness/maintainability reviews completed. Fixed the sole legacy-action regression and made invalid timing consistently unknown; removed newly unused statusBarTitle/moduleSummary/summary paths. +- Native UI is implemented but unproven visually: no GUI, screenshots, real Terminal/import, installation or live VPN acceptance was run. Existing unrelated dirty changes remain intact. diff --git a/docs/goals/configured-auth-ui/GOAL.md b/docs/goals/configured-auth-ui/GOAL.md new file mode 100644 index 0000000..bc37843 --- /dev/null +++ b/docs/goals/configured-auth-ui/GOAL.md @@ -0,0 +1,3 @@ +# Goal: One configured login action + +Use Krypton Execution on `docs/goals/configured-auth-ui/PLAN.md`. The user approved equal full automatic login for Bitwarden and a local imported key. Keep authentication truth in CLI/env, update all runtime/installer/import paths, preserve prior dirty work and validate through isolated automated fixtures. Native visual/live acceptance is not authorized. diff --git a/docs/goals/configured-auth-ui/PLAN.md b/docs/goals/configured-auth-ui/PLAN.md new file mode 100644 index 0000000..a143f54 --- /dev/null +++ b/docs/goals/configured-auth-ui/PLAN.md @@ -0,0 +1,44 @@ +# Configured Authentication and Clear Menu Implementation Plan + +**Intent:** Make the saved login approach explicit and make Connect always use it; fix faint/uneven status icons shown in the supplied screenshot. +**Current Behavior:** The connect arrow chooses a one-off override, the saved approach is unclear while connected, Bitwarden uses hidden auto-submit while local imported OTP uses visible/manual submit. Ring track is faint and a round tiny arc looks like an isolated dot. +**Expected Outcome:** A persistent Manual/Automatic setting, with Automatic source Key on this Mac/Bitwarden. Both automatic sources use hidden autofill/OTP/submit (explicitly confirmed by the user). One Connect button without a launch-mode menu. All status symbols fit a consistent 16pt box; neutral visible track and non-rounded progress cap. +**Target-Perspective Output:** Synthetic save/status/launch checks prove that each selection survives restart/update, Connect uses stored choice and both auto sources produce the same launch flags. Swift build and existing regressions pass. Screenshot is user-provided evidence; no new screenshots or GUI checks. +**Truth Owner:** CLI/env own saved auth choice and last automatic source; Swift only sends a setter command and renders returned status. Existing Keychain and importer still own secrets. +**Contract Boundary:** Add canonical `keychain-auto`; retain `manual-keychain`, `bitwarden-auto`, legacy CLI aliases and additive status metadata. New `--set-auth=manual|auto|keychain|bitwarden` saves configuration only. The UI clears inherited auth-selector env overrides and passes no auth override when connecting. +**Cutover:** Existing `manual-keychain + LOCAL_OTP=1` resolves to keychain-auto under the newly approved behavior; explicit manual aliases force LOCAL_OTP=0. Installer preserves and renders the canonical profile; successful import activates keychain-auto. +**Displaced Path:** Remove the connect dropdown and one-off choices from the app UI. Replace old manual-local submit behavior with the user-approved automatic behavior. No parallel Swift preferences for auth. +**Value Density:** Keep existing CLI, Keychain, PyOTP and runtime patches. Use native pickers and an atomic env setter, not another auth service. +**Acceptance Evidence:** Automated temporary-home selection/save/status tests, fake client launch matrix, importer regressions, settings preservation, native build, icon source/geometry review and POST correctness review. +**Evidence Lane:** Automated checks and supplied screenshot inspection only. No installed config changes, real Keychain, live VPN, app/GUI launch or screenshots. +**Kill Criteria:** Connect never picks the first available override; the active setting remains visible in every state; both auto sources have identical browser/submit flags; failed save cannot falsely update the UI; changing settings cannot reconnect an active session; no unsupported claim that a local secret necessarily came from Yandex. +**Architecture Slice:** CLI normalization/status/setter/preflight/launch -> Swift saved settings UI; importer/installer template migration; status label drawing. Existing unrelated dirty work, DNS, SSO selectors and reconnect policy are excluded. +**Plan Review Gate:** Requires PRE review before execution. + +## Tasks + +1. Root adds keychain-auto, atomic setter and auth status metadata. `LEMANA_VPN_AUTO_SOURCE` records the preferred automatic source so toggling manual/automatic preserves the last source; it is not a separate active mode. Writes update owned MODE/LOCAL_OTP/AUTH_PROFILE/CREDENTIAL_SOURCE/USE_BITWARDEN/AUTO_SOURCE together and preserve other settings. Setter runs before connection or patch side effects, and never reads secret values. +2. Root updates installer defaults/templates/migration and importer activation/copy. Local source is labeled “Ключ на этом Mac” because Bitwarden and import share the existing Keychain entry. Preflight gives source-specific setup guidance; missing credentials stop auto launch instead of prompting invisibly. +3. Root replaces the app dropdown with one configured connect action and native saved-mode/source controls. Save requests disable concurrent save/connect/import; only successful CLI status updates the selection. An active connection keeps running; settings apply next time. Normalize icon boxes/contrast/caps from supplied evidence. +4. Root adds focused fixture tests, updates earlier expectations intentionally changed by full auto, runs regression ladder and records native visual acceptance as untested. Read-only agents perform PRE/POST and correctness/maintainability review. + +## Approved behavior + +| UI choice | Canonical mode | Password/code source | Browser / submit | +| --- | --- | --- | --- | +| Вручную | manual-keychain | Saved password + manually entered OTP | shown / off | +| Автоматически, Ключ на этом Mac | keychain-auto | Existing Keychain username/password/TOTP | hidden / on | +| Автоматически, Bitwarden | bitwarden-auto | Existing Bitwarden sync to Keychain | hidden / on | + +`--manual-full` stays a diagnostic no-autofill command. `--debug` still makes the browser visible. The app will explain a missing/incompatible CLI and disable mode editing until refreshed; there is no automatic fallback to a different mode. + +## Completed evidence + +- UI now has two persisted modes and a separate automatic-source selector. Connect has no dropdown and sends no mode override. Status refresh is the only settings reader in Swift; connection events cannot overwrite saved settings. Saving, incomplete setup and in-progress authentication are guarded appropriately, with visible save errors. +- Canonical keychain-auto, approved legacy-local migration, importer activation, installer template/wizard and remembered auto source are integrated. Both automatic sources share the hidden/OTP/submit launch branch. The setter changes only the env file and preserves unrelated settings. +- Supplied screenshot/code review identified a faint track plus rounded short arc, rather than a demonstrable off-center circle. Track is now adaptive neutral at 0.45 alpha, progress cap is butt, and system/menu symbols use consistent boxes. No new native visual inspection was run. +- `tests/auth_settings.py`: PASS for all saved choices, last-auto-source restoration, failure/no side effects, local readiness and explicit manual override. +- `tests/smoke.sh`: PASS, including actual setter → ordinary no-override fake-client launch for manual, local automatic and Bitwarden automatic; both automatic sources produce hidden browser and submit enabled. +- `tests/configuration.py`: 11 checks PASS, including profile migration/update and explicit manual override. Importer, menu/timing/transport and logging regression checks PASS. Shell syntax and `git diff --check` PASS. +- Final `swift build -c release --package-path app`: PASS (3.75 s). PRE and POST correctness/maintainability reviews passed after fixing stale connection-module snapshots and hidden save errors. +- No real installation, live VPN, secret-store operation or GUI testing was performed. Native visual quality and real automatic SSO remain unverified in this turn; prior unrelated dirty work is preserved. diff --git a/docs/goals/logging-and-config/GOAL.md b/docs/goals/logging-and-config/GOAL.md new file mode 100644 index 0000000..6d24c7d --- /dev/null +++ b/docs/goals/logging-and-config/GOAL.md @@ -0,0 +1,3 @@ +# Goal: Bounded logs and reliable settings + +Execute `docs/goals/logging-and-config/PLAN.md`, preserving existing dirty authentication work. Keep one log writer per owner, CLI-owned settings, and backward-compatible events. Capture deterministic CLI/filesystem acceptance evidence; no GUI, live VPN or real install is authorized. Report any unproved behavior explicitly. diff --git a/docs/goals/logging-and-config/PLAN.md b/docs/goals/logging-and-config/PLAN.md new file mode 100644 index 0000000..d4e0dc7 --- /dev/null +++ b/docs/goals/logging-and-config/PLAN.md @@ -0,0 +1,51 @@ +# Bounded Logs and Reliable Settings Implementation Plan + +**Intent:** Stop unbounded disk usage and make existing settings predictable without changing authentication or tunnel behavior. +**Current Behavior:** Both log writers append forever. Installer interpolation corrupts special characters and replaces local settings; unknown runtime flags can fall through to connection. +**Expected Outcome:** Each log has a bounded current file and one bounded previous file (5 MiB each by default); custom settings survive updates; settings round-trip literally; mistyped commands fail before connecting. +**Target-Perspective Output:** Isolated CLI/filesystem examples show capped current/archive sizes and recent records, valid JSON with quoted settings, preserved configuration after two renders, and a rejected unknown flag. +**Truth Owner:** CLI env for runtime settings and the existing TOML for SSO. CLI owns the log limit reported to Swift; each process owns its log writer. +**Contract Boundary:** Keep current status/events/auth modes, adding optional logging metadata. Installer preserves unowned env lines and existing TOML profile/rules while updating the selected mode and username. +**Cutover:** Replace append-only writers in place; retain existing log names and add only `.1`. Do not mutate the installed setup or real logs during development. +**Displaced Path:** Raw sed template interpolation and unbounded writes are removed, with no parallel logging backend or new dependency. +**Value Density:** Bounded storage, correct literal settings, and update preservation address observable defects; avoid a general settings framework and wholesale shell/Swift rewrite. +**Acceptance Evidence:** Before/after automated regression checks using temporary files/homes and fake clients; shell smoke and Swift release build. Include long-running writes, oversized existing files/records, log I/O failure, quoted settings, update preservation, invalid flags. +**Evidence Lane:** Automated local CLI/filesystem only. No GUI, live connection, installation, Keychain writes, or deletion of real logs. +**Kill Criteria:** No append-only production writer; no raw sed settings interpolation; no unknown-flag path into connect; tests exercise the changed behavior. +**Architecture Slice:** `bin/vpn-lemanapro.sh` -> raw client stream/log + status JSON -> `VPNManager.swift` -> bounded app log. `install.sh` -> env templates/TOML -> same CLI. Authentication patches, DNS cleanup, health/reconnect semantics and unrelated dirty work are excluded. +**Plan Review Gate:** Requires PRE review before execution. + +## Tasks and ownership + +1. Root: bounded shell writer in `bin/vpn-lemanapro.sh`, Foundation-only `BoundedLog.swift` used by `VPNManager.swift`, log-limit setting and optional JSON metadata. Test both writers with actual temporary files, including existing oversized logs, repeated rollover and write failures; preserve event parsing. Unknown runtime flags fail with status 2. Literal JSON encoding for BW item. Fix `_prompt_read` EOF propagation and explicitly stop every caller before subsequent persistence/credential actions; empty Enter keeps existing behavior. Test username, secret and save-choice EOF with fake input and a timeout. Do not change auth modes/sources, health or reconnect semantics. +2. Configuration agent (parallel, disjoint): `install.sh`, env templates, new isolated configuration regression check. Precedence: flags > invocation env > saved env > defaults for supported installer settings; preserve arbitrary runtime settings and TOML custom profile/rules. Replace raw sed interpolation with stdlib literal escaping, reusing existing quoting conventions. Verify a second render preserves custom settings and special characters; installer environment mode takes effect. Do not edit runtime, Swift, README or smoke test. +3. Root integration: wire small regression checks into existing automated workflow as appropriate, document editable settings, precedence and rotation in README. Fix only evidence-backed issues in changed paths. Record remaining audit findings instead of opportunistic auth/refactoring work. +4. Read-only reviewer: POST contract/correctness/maintainability review. Root resolves blockers and runs syntax checks, focused regressions, `tests/smoke.sh`, `swift build -c release --package-path app`, `git diff --check`. + +## Risks and evidence + +`LEMANA_VPN_LOG_MAX_BYTES` defaults to 5242880; accept decimal integers 1..999999999, reject empty explicit values, zero, negative and malformed values before side effects. Swift defaults to 5242880 before status or with an old CLI and uses the validated optional CLI value thereafter. Verify saved env -> status JSON -> Swift decoding/writer setting. PRE review findings above are incorporated; proceed to execution. + +| Contract | Risk | Independent oracle | +| --- | --- | --- | +| Log size and recent history | Disk growth, copying giant legacy file | Current and `.1` each <= configured byte limit, newest record retained, only two files | +| Log failures | VPN output consumer exits | Fake output still produces expected JSON event with unwritable log destination | +| Settings round-trip/update | Corruption, command substitution, silent resets | Exact recovered values, sentinel command never executed, custom TOML values preserved | +| CLI validation | Typo initiates SSO | Exit 2 before client/status file creation | +| Compatibility | Existing dirty auth work regresses | Baseline vs final smoke results and Swift build, live acceptance explicitly unrun | + +## Deferred audit findings + +- Arbitrary `OPENCONNECT_LITE_CONFIG_DIR` and XDG runtime path need a separate end-to-end contract; do not mask this with status-only changes. +- The pre-existing CLI `_persist_username` writer selects the first username-like TOML line; unlike the revised installer it is not scoped to `[credentials]`. Custom profiles containing another username need a follow-up shared configuration-write contract and regression before broadening editable SSO settings. +- Broader extraction of embedded SSO patches and reconnect/state-machine changes require their own evidence and are outside this slice. + +## Execution evidence + +- Baseline: shell syntax, existing smoke, release Swift build and diff whitespace checks passed before edits. +- Historical app log was measured read-only at 2,552,898,484 bytes. Repeated closed-terminal credential prompts dominated the sampled tail. Current baseline still reproduced a closed-input loop; the new regression times out on that baseline and passes with explicit EOF propagation. +- `python3 tests/configuration.py`: 10 checks pass, covering literal round-trips, saved settings, precedence, legacy inputs, TOML variants and fresh help without Python. The first six regression cases all failed against the saved baseline installer. +- `python3 tests/logging.py`: passes actual CLI/Swift file writes, bounded legacy/repeated/oversized records, reduced limits, private permissions, closed username/password/TOTP/Bitwarden/consent input, preserved empty Enter, JSON output on log failure, settings decoding and rejected flags/limits. +- Final shell syntax, `tests/smoke.sh` (`smoke ok`), `swift build -c release --package-path app` and `git diff --check`: PASS. +- PRE/POST correctness and maintainability reviews completed; findings in the changed slice resolved. CLI ordinary-write microbenchmark improved from the first implementation's 4.800 s to 1.806 s per 300 records (old append-only baseline 0.831 s); the remaining overhead checks file size before writing. +- Real logs and installed files were not changed. No GUI, live VPN, installation or credential-store operation was performed. Live connection acceptance remains untested. diff --git a/docs/goals/manual-first-auth-flow/GOAL.md b/docs/goals/manual-first-auth-flow/GOAL.md index d94690e..af4bacb 100644 --- a/docs/goals/manual-first-auth-flow/GOAL.md +++ b/docs/goals/manual-first-auth-flow/GOAL.md @@ -1,13 +1,5 @@ -# Goal: Manual-First Auth Flow +# Goal Superseded -Use Krypton Execution to execute `docs/goals/manual-first-auth-flow/PLAN.md`. +Use `docs/goals/two-auth-modes/GOAL.md` instead. -Core rules: -- Treat PLAN.md as the source plan. -- Preserve intent, ownership, contract, cutover, evidence, and kill criteria. -- Make fresh install and default `vpn` / app connect manual-first. -- Keep the installer understandable for a non-IT user: plain wording, manual mode on Enter, optional conveniences explained as choices. -- Keep Bitwarden, Touch ID, saved TOTP, autosubmit, and headless mode as explicit opt-in features. -- Do not add a new dominant path without deleting, redirecting, demoting, or shimming the displaced Bitwarden/auto-first path. -- Capture acceptance evidence from a clean temporary HOME and the menu-bar app contract. -- Say "implemented but unproven" if that evidence cannot be captured. +The older manual-first goal is intentionally replaced by the two-mode contract. diff --git a/docs/goals/manual-first-auth-flow/PLAN.md b/docs/goals/manual-first-auth-flow/PLAN.md index f11773e..06a48d8 100644 --- a/docs/goals/manual-first-auth-flow/PLAN.md +++ b/docs/goals/manual-first-auth-flow/PLAN.md @@ -1,440 +1,10 @@ -# Manual-First Auth Flow Implementation Plan +# Manual-First Auth Flow Plan Superseded -**Intent:** Перевернуть Lemana VPN из auto/Bitwarden-first в manual-first: новая установка и действие по умолчанию открывают видимый SSO-браузер без сохранённых секретов, а удобства включаются отдельными функциями. -**Current Behavior:** Fresh install по умолчанию выбирает `credential_source=bitwarden`, ставит Bitwarden/Touch ID, `vpn` запускает hidden browser с autofill+submit, а `manual-full` существует как отдельный диагностический режим. -**Expected Outcome:** Базовый путь не требует Bitwarden, Keychain, TOTP seed или автоотправки. Пользователь может поэтапно включить сохранение LDAP login/password в macOS Keychain, затем TOTP seed/autofill, затем Bitwarden sync, Touch ID, autosubmit/headless. -**Target-Perspective Output:** Новый пользователь запускает installer, ничего специально не выбирает, нажимает `vpn` или основную кнопку в `LemanaVPN.app`, видит Keycloak форму и вводит LDAP, пароль и одноразовый код руками. Если он включил сохранение LDAP в Keychain, username/password подставляются, а одноразовый код он вводит руками. -**Truth Owner:** `bin/vpn-lemanapro.sh` владеет runtime-решением режима; `~/.config/lemana-vpn/env` хранит выбранные capabilities; macOS Keychain хранит только секреты; Swift app только вызывает CLI и читает JSON. -**Contract Boundary:** Installer пишет env/config, CLI читает env/flags/Keychain и отдаёт JSON Lines/status JSON, Swift app потребляет только этот CLI-контракт. `openconnect-lite` остаётся SSO/VPN engine. -**Cutover:** Fresh installs become manual-first. Existing configs with `LEMANA_VPN_CREDENTIAL_SOURCE=bitwarden` keep working, but docs/UI stop presenting Bitwarden as default. Legacy aliases `vpn-auto`, `vpn-manual`, `vpn-manual-full` stay as compatibility shims. -**Displaced Path:** The displaced dominant path is `Bitwarden + Touch ID + hidden autofill + autosubmit by default`. It becomes an explicit opt-in feature set, not the default route. -**Value Density:** First slice removes the biggest onboarding failure: users without Bitwarden can connect manually immediately, then add only the conveniences they need. -**Acceptance Evidence:** In a clean temporary HOME, `sh install.sh --dry-run --non-interactive` reports manual/default auth with Bitwarden and Touch ID off; the interactive installer copy reads like a step-by-step setup for a non-IT user; `bash bin/vpn-lemanapro.sh --json` without credentials reaches a visible browser launch without `username_required` or `keychain_required`; a Keychain-login-only fixture fills username/password but leaves OTP manual and submit disabled; the Swift app primary action maps to the manual-first path. -**Evidence Lane:** Non-live smoke ladder first: `sh -n`, `bash -n`, `tests/smoke.sh`, `swift build`, `git diff --check`. Live VPN is optional after status check and should start with visible manual mode only. -**Kill Criteria:** No fresh-install default may select Bitwarden, require a TOTP seed, autosubmit, or hide the browser. No docs may state Bitwarden is enabled by default. No default CLI/app path may require saved credentials before opening manual SSO. -**Architecture Slice:** Installer defaults + CLI auth profile/capability model + Swift launch mode labels + README/smoke coverage. -**Plan Review Gate:** Requires PRE review before execution. +This plan is superseded by `docs/goals/two-auth-modes/PLAN.md`. -## Короткий План +Do not execute this older plan. It described an intermediate four-profile model. The current approved contract keeps exactly two public modes: -🎯 Цель: fresh install, `vpn` и основная кнопка приложения стартуют с полностью ручного SSO; сохранение LDAP, TOTP, Bitwarden, autosubmit и headless включаются отдельно. +- `manual-keychain` +- `bitwarden-auto` -📦 Репозитории: только `/Users/dokril/git/home/lemana-vpn`. - -🧩 Модули: `install.sh`, `bin/vpn-lemanapro.sh`, `app/Sources/LemanaVPN`, `tests/smoke.sh`, `README.md`; `templates/openconnect-lite-config.toml` только если login-only autofill потребует правки правил. - -🛠 Основные изменения: -- Переключить fresh defaults с Bitwarden/auto-first на manual-first. -- Ввести явный auth profile/capability contract: manual, saved-login, saved-totp, auto. -- Разрешить Keychain хранить только LDAP username/password без обязательного TOTP seed. -- Оставить Bitwarden, Touch ID, autosubmit/headless как opt-in функции. -- Сделать Swift app CLI-wrapper поверх тех же режимов, с manual-first primary action. -- Зафиксировать всё в smoke-тестах и README. - -✅ Проверка: `sh -n install.sh`, `sh -n uninstall.sh`, `bash -n bin/vpn-lemanapro.sh`, `sh -n tests/smoke.sh`, `tests/smoke.sh`, `swift build -c release --package-path app`, `git diff --check`. - -⚠️ Риски: старые пользователи могут ожидать auto-connect на `vpn`; partial Keychain без TOTP надо проверить fake launch тестом и, при необходимости, видимым manual smoke. - -➡️ Следующий шаг: начать с `install.sh` и зафиксировать новый env/flag contract для manual-first defaults. - -## Architecture Slice - -Files to create: - -- None required for runtime. This goal package is the planning artifact. - -Files to modify: - -- `install.sh` - defaults, wizard wording, flags, env rendering, dry-run output. -- `bin/vpn-lemanapro.sh` - auth profile/capability model, default mode, partial Keychain support, JSON events. -- `app/Sources/LemanaVPN/VPNManager.swift` - launch mode enum/default, JSON handling if new events are added. -- `app/Sources/LemanaVPN/LemanaVPNApp.swift` - menu labels/order so manual-first is primary and auto is secondary. -- `tests/smoke.sh` - regression coverage for fresh defaults, manual launch without credentials, partial Keychain, app wiring. -- `README.md` - user-facing feature matrix and migration/update instructions. -- `templates/openconnect-lite-config.toml` only if login-only filling needs rule adjustments; otherwise avoid. - -Files to avoid: - -- `libexec/lemana-vpn-dns-cleanup` unless DNS behavior breaks. -- `uninstall.sh` except if new Keychain account names require cleanup. -- Direct edits inside installed `openconnect-lite`; use the existing runtime patch path from `bin/vpn-lemanapro.sh`. - -Source of truth: - -- Repo source for behavior. -- Installed env file for user-selected capabilities. -- Keychain for LDAP password and optional TOTP seed. - -Read path: - -- `install.sh` writes `~/.config/lemana-vpn/env`. -- `bin/vpn-lemanapro.sh` sources env, applies CLI flag overrides, checks Keychain capability presence, then launches `openconnect-lite`. -- `LemanaVPN.app` calls `~/bin/vpn-lemanapro.sh --json `. - -Write path: - -- `vpn --configure-login` or equivalent writes username/password only. -- `vpn --configure-keychain` remains the full saved-credentials path and writes password plus permanent TOTP seed. -- Bitwarden sync, when enabled, writes password plus optional TOTP seed into Keychain. - -Contract boundary: - -- CLI flags and JSON events are the public contract for the app and tests. -- Suggested new runtime contract: - - `auth_profile=manual`: visible browser, no preflight, no autofill, no submit. - - `auth_profile=saved-login`: visible browser, username/password autofill, OTP manual, no submit. - - `auth_profile=saved-totp`: visible browser, username/password/TOTP autofill, no submit. - - `auth_profile=auto`: hidden or visible automatic mode, full autofill and submit; explicit only. - - `credential_source=none|keychain|bitwarden`: where saved values come from, separate from whether submit/headless are enabled. - -Integration points: - -- macOS Keychain service `openconnect-lite`. -- Optional Bitwarden CLI item `LM LDAP`. -- `openconnect-lite` config autofill rules. -- Swift app menu and reconnect behavior. -- Existing aliases from shell install block. - -Migration/cutover: - -- Fresh installs write `credential_source=none` and `auth_profile=manual`. -- Existing `credential_source=bitwarden` installs continue as saved-totp/auto-capable, but `vpn` default should still prefer manual-visible unless the user explicitly chooses auto. -- `vpn-auto` remains the explicit old behavior. -- `--manual-full` remains compatibility alias for the new default manual profile. - -Displaced path: - -- Installer Enter=Bitwarden. -- CLI `CONNECT_MODE=auto`. -- Full password+TOTP seed as mandatory preflight for non-`manual-full`. -- App primary/default connect action pointing at `.auto`. - -Acceptance evidence gate: - -- A clean temp HOME proves fresh defaults. -- Captured interactive installer output proves that the default path is understandable without knowing Bitwarden, Keychain, TOTP seed, or `credential_source`. -- Fake `openconnect-lite` launch capture proves display/autofill/click env for each profile. -- App source/smoke proves primary UI wiring. -- Installed-bundle verification is required only when refreshing the local app after implementation. - -## Пользовательский Процесс Установки - -Цель этого сценария: человек, далёкий от IT, должен понимать, что сейчас произойдёт, что от него требуется, и что можно пропустить. Installer не должен начинать с технического выбора credential source. - -### Первый Экран - -Текст должен быть коротким: - -```text -Lemana VPN установит приложение для подключения к корпоративному VPN. - -По умолчанию ничего не сохраняется: при подключении откроется окно входа, -а вы введёте логин, пароль и одноразовый код сами. - -Дополнительные удобства можно включить сейчас или позже. -``` - -Основное действие по Enter: продолжить с ручным безопасным режимом. - -Запрещено на первом экране: - -- `credential_source` -- `auth_profile` -- `TOTP seed` -- `openconnect-lite` -- `Bitwarden item` -- `headless` - -### Шаг 1: Что Будет Установлено - -Installer показывает не список пакетов, а понятные пункты: - -```text -Будет установлено: -- приложение Lemana VPN в меню macOS; -- команда vpn для подключения из Terminal; -- VPN-компонент, который открывает корпоративную страницу входа; -- безопасная очистка DNS после отключения. -``` - -Технические зависимости (`openconnect`, `pipx`, `openconnect-lite`) можно показывать только в подробном логе ниже или в debug/dry-run. - -### Шаг 2: Базовый Режим Входа - -Вопрос: - -```text -Как подключаться по умолчанию? - -1) Вводить всё вручную (рекомендуется) - Откроется окно входа. Вы сами введёте логин, пароль и одноразовый код. - -2) Запомнить логин и пароль на этом Mac - При входе логин и пароль подставятся сами. Одноразовый код вы введёте вручную. - -3) Настроить автоматический вход - Нужно заранее сохранить пароль и постоянный код настройки 2FA. - -Выбор [1/2/3, Enter=1]: -``` - -Поведение: - -- `1` ставит `auth_profile=manual`, `credential_source=none`. -- `2` ставит `auth_profile=saved-login`, `credential_source=keychain`, после установки запускает настройку LDAP username/password. -- `3` открывает следующий уточняющий шаг и не должен быть default. - -### Шаг 3: Автоматический Вход Только Для Продвинутого Пути - -Если выбран пункт 3, installer объясняет риск простым языком: - -```text -Автоматический вход работает только если на Mac сохранены: -- корпоративный пароль; -- постоянный код настройки 2FA. - -Это не текущие 6 цифр из приложения-аутентификатора. -Если вы не знаете, что это такое, выберите ручной режим. -``` - -Варианты: - -```text -1) Вернуться к ручному режиму -2) Сохранить пароль и постоянный код 2FA в macOS Keychain -3) Взять пароль и код 2FA из Bitwarden -``` - -Поведение: - -- `1` возвращает к `auth_profile=manual`. -- `2` ставит `auth_profile=saved-totp`, `credential_source=keychain`, запускает full Keychain setup. -- `3` ставит `credential_source=bitwarden`; Touch ID спрашивается отдельным простым вопросом. - -### Шаг 4: Bitwarden Как Дополнительная Функция - -Bitwarden не должен выглядеть обязательным. Вопрос появляется только после явного выбора Bitwarden: - -```text -Использовать Bitwarden для хранения VPN-пароля? - -Подойдёт, если у вас уже есть запись с корпоративным VPN-паролем -и постоянным кодом настройки 2FA. -``` - -Если Bitwarden CLI не найден: - -```text -Bitwarden не найден на этом Mac. -Можно установить его сейчас или вернуться к ручному режиму. -``` - -Default: вернуться к ручному режиму, если пользователь не уверен. - -### Шаг 5: Touch ID Только После Bitwarden - -Вопрос: - -```text -Разрешить Touch ID для открытия Bitwarden? - -Это не VPN-пароль. Touch ID только помогает достать данные из Bitwarden. -``` - -Default: нет, если пользователь не выбирал Bitwarden; да/нет можно спрашивать только в Bitwarden path. - -### Шаг 6: Понятный Прогресс Установки - -Progress log должен говорить человеческим языком: - -```text -Проверяю компоненты для VPN... -Устанавливаю приложение Lemana VPN... -Добавляю команду vpn... -Настраиваю безопасное отключение VPN... -Готово. -``` - -Если macOS просит пароль администратора, installer заранее объясняет: - -```text -macOS может запросить пароль от компьютера. -Он нужен, чтобы разрешить VPN подключаться и корректно очищать DNS после отключения. -``` - -### Финальный Экран - -Для ручного режима: - -```text -Готово. Как подключиться: -1. Откройте Lemana VPN из Applications или меню macOS. -2. Нажмите "Подключить". -3. В открывшемся окне введите корпоративный логин, пароль и одноразовый код. - -Проверить состояние: vpn --status -``` - -Для режима с сохранённым логином и паролем: - -```text -Готово. При подключении логин и пароль будут подставлены автоматически. -Одноразовый код нужно ввести вручную. -``` - -Для автоматического режима: - -```text -Готово. Автоматический вход включён. -Если он не сработает, используйте ручной режим: vpn --manual-full -``` - -### Ошибки И Подсказки - -Ошибки должны говорить, что делать дальше: - -- Нет сохранённого пароля: `Запустите vpn --configure-login или подключитесь вручную.` -- Нет постоянного кода 2FA для auto mode: `Автоматический вход не настроен. Выберите ручной режим или добавьте постоянный код настройки 2FA.` -- Bitwarden заблокирован в приложении без Terminal: `Откройте Terminal и выполните vpn, либо подключитесь вручную.` -- Пользователь выбрал непонятный вариант: `Введите 1, 2 или 3. Если не уверены, нажмите Enter.` - -### Acceptance Evidence Для Installer UX - -- Interactive dry-run через `expect` должен захватить первый экран, выбор режима и финальную подсказку. -- Smoke должен проверять, что Enter выбирает ручной режим. -- README должен показывать тот же сценарий, что и installer. -- В обычном wizard не должно быть слов `credential_source`, `auth_profile`, `TOTP seed`; они допустимы только в help/debug/docs for advanced. - -## Дополнительные Функции - -1. **Core manual SSO (default)** - - Что делает: открывает видимый браузер Keycloak, не читает Bitwarden/Keychain, не заполняет поля, не нажимает submit. - - Когда включается: всегда на fresh install и при `vpn` без дополнительных настроек. - - Когда не включается: если пользователь явно запускает `vpn-auto` или выбрал auto profile. - -2. **Saved LDAP login/password in macOS Keychain** - - Что делает: сохраняет LDAP username/password в Keychain и подставляет их в видимую форму. - - Когда включается: пользователь явно запускает настройку сохранения LDAP или выбирает этот пункт в installer. - - OTP: текущий одноразовый код вводится руками; TOTP seed не требуется. - -3. **Saved TOTP seed** - - Что делает: сохраняет постоянный TOTP seed и позволяет `openconnect-lite` генерировать текущий код для autofill. - - Когда включается: пользователь явно добавил seed через full Keychain setup или Bitwarden sync. - - Ограничение: текущий 6-значный код нельзя сохранять как настройку. - -4. **Autofill** - - Что делает: заполняет те поля, для которых есть capability: username/password, а затем optional TOTP. - - Когда включается: при `saved-login` или `saved-totp`. - - Submit: по умолчанию выключен; пользователь нажимает вход сам. - -5. **Autosubmit/headless** - - Что делает: запускает старый удобный путь с hidden browser, полным autofill и нажатием submit. - - Когда включается: только явным `vpn-auto`, `--auto`, profile `auto` или отдельным opt-in флагом. - - Предусловие: saved login/password и TOTP seed должны быть доступны; без TOTP seed этот режим должен fail fast с понятной ошибкой. - -6. **Bitwarden sync** - - Что делает: читает LDAP password и TOTP seed из Bitwarden item, нормализует TOTP seed и перекладывает в Keychain. - - Когда включается: только если пользователь выбрал Bitwarden provider. - - Fallback: если `bw` отсутствует или locked в GUI/no-tty, использовать уже сохранённый Keychain либо manual path, не блокировать default. - -7. **Touch ID helper** - - Что делает: локально защищает чтение Bitwarden master password. - - Когда включается: только вместе с Bitwarden provider и явным согласием пользователя. - - Не делает: не заменяет LDAP password и не является хранением VPN credentials. - -## Tasks - -### Task 1: Rewrite user-facing contract and docs - -- Scope: `README.md`. -- Change: describe manual-first default, feature matrix, migration from old Bitwarden-first install, and the non-IT installation scenario from this plan. -- Expected output: docs no longer say Bitwarden/auto are default; examples show `vpn` as manual and `vpn-auto` as opt-in; installation instructions use the same wording as the installer. -- Verification: `rg -n "по умолчанию|Bitwarden|vpn-auto|manual-full|одноразовый код|ручной режим" README.md`. -- Acceptance evidence: a new user can read the first install section and understand what will be installed, what they will type during first connect, and that Bitwarden is optional. -- Parallel: yes, but must be reconciled with installer flag names from Task 2. - -### Task 2: Change installer defaults and capability selection - -- Scope: `install.sh`. -- Change: default credential source becomes none/manual; Bitwarden and Touch ID default off; wizard Enter keeps manual; add or reuse flags for saved LDAP, full Keychain, Bitwarden provider, and auto profile; rewrite interactive copy using the "Пользовательский Процесс Установки" section. -- Expected output: dry-run shows manual/default auth and no Bitwarden/Touch ID install unless selected; interactive prompts say "вводить всё вручную", "запомнить логин и пароль", and "автоматический вход" instead of exposing low-level config names. -- Verification: `sh -n install.sh`; `sh install.sh --dry-run --non-interactive`; interactive dry-run through `expect` if available. -- Acceptance evidence: clean install dry-run does not try to install Bitwarden and does not schedule Keychain credential prompts by default; captured interactive output is understandable without IT vocabulary and Enter chooses manual mode. -- Parallel: no, because it defines env contract consumed by CLI/tests. - -### Task 3: Refactor CLI auth profiles and partial Keychain support - -- Scope: `bin/vpn-lemanapro.sh`. -- Change: replace auto-first/default credential preflight with an auth-profile resolver; add partial Keychain support for saved login without TOTP; keep full Keychain and Bitwarden sync as opt-ins. -- Expected output: no-credential default reaches visible manual browser; saved-login fills username/password and leaves OTP manual; saved-totp can fill OTP but still does not submit by default. -- Verification: `bash -n bin/vpn-lemanapro.sh`; fake `openconnect-lite` capture in `tests/smoke.sh`. -- Acceptance evidence: JSON events clearly state active auth profile and missing optional capabilities without treating them as fatal in manual profiles. -- Parallel: no, central truth owner. - -### Task 4: Preserve automatic compatibility without keeping it dominant - -- Scope: `bin/vpn-lemanapro.sh`, `install.sh`, shell aliases. -- Change: keep `vpn-auto`/`--auto` as explicit old behavior; guard autosubmit/headless behind full saved credentials; keep `--manual-full` compatibility alias for the default manual profile. -- Expected output: current power users can still run the old path intentionally. -- Verification: `tests/smoke.sh` assertions for `vpn-auto`, `--auto`, `--manual-full`, launch env. -- Acceptance evidence: default path and auto path are both test-covered and visibly separate. -- Parallel: can run after Task 3. - -### Task 5: Update Swift menu-bar app surface - -- Scope: `app/Sources/LemanaVPN/VPNManager.swift`, `app/Sources/LemanaVPN/LemanaVPNApp.swift`. -- Change: make the primary menu action manual-first; demote automatic connect to an explicit secondary action; keep app as a CLI wrapper; surface missing saved credentials as setup guidance, not hidden prompts. -- Expected output: app default action does not trigger Bitwarden or autosubmit unless the user chooses an explicit auto/saved mode. -- Verification: `swift build -c release --package-path app`; smoke greps for the new labels/mode wiring. -- Acceptance evidence: app source and built binary contain the manual-first label and map it to the manual profile. -- Parallel: yes after CLI mode names are stable. - -### Task 6: Expand smoke coverage - -- Scope: `tests/smoke.sh`. -- Change: update old assertions and add cases for fresh manual default, saved-login-only, saved-totp, Bitwarden opt-in, and app wiring. -- Expected output: smoke becomes the executable spec for the feature matrix and installer UX. -- Verification: `sh -n tests/smoke.sh`; `tests/smoke.sh`. -- Acceptance evidence: smoke fails if Bitwarden or auto become fresh defaults again, or if the basic wizard no longer defaults to manual mode with non-technical wording. -- Parallel: yes after Task 2 and Task 3 contracts are known. - -### Task 7: Final verification and local update notes - -- Scope: whole repo; installed app only if doing a local refresh. -- Change: run non-live ladder, then optionally install/update local checkout with `sh install.sh` after user approval for real local changes. -- Expected output: plan implemented with evidence and a clear "live VPN not run" or live manual evidence. -- Verification: - - `sh -n install.sh` - - `sh -n uninstall.sh` - - `bash -n bin/vpn-lemanapro.sh` - - `sh -n tests/smoke.sh` - - `tests/smoke.sh` - - `swift build -c release --package-path app` - - `git diff --check` -- Acceptance evidence: final answer includes how to run, how to check, how to update installed setup, and what live checks were intentionally skipped. -- Parallel: no, final integration gate. - -## Non-Goals - -- Do not replace `openconnect-lite` or implement a separate VPN client in Swift. -- Do not store current 6-digit OTP codes. -- Do not make the GUI collect secrets directly. -- Do not remove existing automatic mode; demote it to explicit opt-in. -- Do not change DNS cleanup behavior as part of this refactor. - -## Risks - -- Existing users may expect `vpn` to auto-connect. Mitigation: keep `vpn-auto` and document the cutover clearly. -- Partial Keychain support may need careful `openconnect-lite` behavior verification when TOTP is absent. Mitigation: fake launch tests first, then one visible manual smoke if needed. -- Swift app could lag behind installed source again. Mitigation: after implementation refresh installed bundle via `sh install.sh` and verify with app source/build or `strings` if doing local install. -- Credential language can confuse Bitwarden master password, LDAP password, TOTP seed, and current OTP. Mitigation: keep labels explicit in CLI and README. - -## Execution Order - -1. Task 2 defines the installer/env contract. -2. Task 3 implements the CLI truth owner. -3. Task 4 preserves explicit auto compatibility. -4. Task 5 updates the app wrapper. -5. Task 6 turns the matrix into smoke coverage. -6. Task 1 updates docs with final flag/profile names. -7. Task 7 verifies and prepares local update instructions. +Use `docs/goals/two-auth-modes/GOAL.md` for execution. diff --git a/docs/goals/startup-dns-and-icons/GOAL.md b/docs/goals/startup-dns-and-icons/GOAL.md new file mode 100644 index 0000000..d5cc206 --- /dev/null +++ b/docs/goals/startup-dns-and-icons/GOAL.md @@ -0,0 +1,19 @@ +# Goal: Recover stale VPN DNS and ship the approved icons + +Use Krypton Execution on `docs/goals/startup-dns-and-icons/PLAN.md`. Preserve user work and auth behavior. Root owns privileged DNS logic and integration; the icon agent has an explicitly disjoint write scope. Prove recovery using synthetic journal/process/DNS fixtures, never real network changes. Report unrun native/reboot acceptance and snapshotless legacy limits. + +## Result — 2026-10-08 + +Implemented in source. Normal installation updates the root helper and ships the native icon renderer. The app gates connection on a capability-checked startup recovery, displays failures/external sessions, and retries through Refresh. CLI exit replaces its finished process before recovery, retaining the client's exit code. DNS snapshots are data-only, versioned, private, durable and serialized with native lockf; no arbitrary private-address reset remains. + +PRE review passed after adding unresolved-journal retention, shared locking and verified owner ancestry. Post-review fixes cover Bash pipeline/progress siblings and custom DNS on newly enabled network services. Final integration review: no outstanding blockers. + +Automated evidence: + +- `python3 tests/dns_recovery.py`: all 16 cases passed; subsequent focused competing-engine regression under the same CLI also passed. Original helper replay fails the new reboot recovery contract as expected. +- `python3 tests/dns_cli.py`: noninteractive command, legacy helper rejection, fixed JSON, path quoting and preserved client exit codes passed. +- `python3 tests/menu.py` and `python3 tests/icons.py`: startup lifecycle, fake CLI, real session timing, both icon themes and offscreen pixel checks passed. +- `tests/smoke.sh`, `python3 tests/configuration.py`, `python3 tests/auth_settings.py`, `python3 tests/logging.py`, and the installed openconnect-lite Python running `tests/yandex_import.py`: passed. +- Shell syntax, `git diff --check` and `swift build -c release --package-path app`: passed. + +Real installation, app/GUI launch, live VPN/DNS changes and actual reboot acceptance were not run. Snapshotless pre-upgrade DNS must first be restored to the user's normal settings; no software can infer an unrecorded custom value. Other network locations, deleted services or invalid journals fail visibly and preserve the record. diff --git a/docs/goals/startup-dns-and-icons/PLAN.md b/docs/goals/startup-dns-and-icons/PLAN.md new file mode 100644 index 0000000..072874f --- /dev/null +++ b/docs/goals/startup-dns-and-icons/PLAN.md @@ -0,0 +1,40 @@ +# Startup DNS Recovery and Approved Icons Implementation Plan + +**Intent:** Install the approved shield icon family with gradual interior fill, and restore normal DNS at app startup after an interrupted VPN session. +**Current Behavior:** App init only refreshes status. vpnc-script persistently changes network-service DNS; abrupt shutdown skips its cleanup and /var/run backups disappear at boot. The existing helper resets any 10.x DNS on three service names and is skipped on ordinary reinstall. Runtime icons still differ from the approved set. +**Expected Outcome:** App startup runs a noninteractive guarded recovery before allowing Connect. A root-owned vpnc wrapper records original DNS and exact VPN DNS before changes, persists the journal across reboot, and restores matching leftovers only when no VPN/SSO is active. Approved vector geometry and real session progress are used by runtime icons. +**Target-Perspective Output:** Isolated reboot/crash fixtures recover recorded DHCP or custom DNS, preserve unrelated/changed DNS, skip active tunnels/SSO, survive reused PIDs and surface failed recovery. Icon bitmap/geometry checks and Swift build prove the native implementation without launching the GUI. +**Truth Owner:** Root-owned DNS wrapper/journal owns before/expected DNS evidence and mutations. CLI owns invocation/events/capability reporting. Swift only requests recovery and reports results. SessionTiming still owns derived icon progress. +**Contract Boundary:** Add `--repair-dns` to CLI; root helper protocol 2 has `--recover`, `--vpnc` and capability inspection. Existing JSON fields remain; DNS capability is additive. App calls recovery only after the CLI advertises support. OpenConnect receives the root wrapper through --script; the wrapper delegates normal routes/DNS setup to installed vpnc-script. +**Cutover:** One root helper serves hook, exit and startup recovery. Remove broad automatic 10.x reset and the CLI's unowned fallback. Installer always updates the root helper. Root journal lives under /var/db, not /var/run. Default runtime icon becomes shield; previously saved ring/clock/time selections remain. +**Displaced Path:** Ad hoc unconditional DNS resets and independent Swift icon shapes. No new daemon, VPN client, credential path, root Python from user-controlled locations or general network-settings API. +**Value Density:** Reuse native networksetup, vpnc-script and existing sudoers wrapper boundary. New files are limited to native icon drawing and focused regression checks; no dependencies. +**Acceptance Evidence:** Real helper source executed with substituted system tools/temp journal, synthetic OpenConnect hook environment and recorded command log; CLI recovery/fake client argument checks; startup wiring/build; headless icon rendering checks and existing suites. +**Evidence Lane:** Automated fixtures only. No actual reboot, live DNS mutation, real VPN, Keychain, app/GUI launch or screenshots. +**Kill Criteria:** Recovery cannot clear arbitrary non-default DNS; current values must match recorded VPN values. Live or indeterminate process checks cannot authorize cleanup. No connection begins during startup recovery. No stale-PID-only guard. New helper and Swift source must ship on normal update. +**Architecture Slice:** `libexec/lemana-vpn-dns-cleanup` + `bin/vpn-lemanapro.sh` + `VPNManager.swift` + installer/template/tests; independent `VPNIcons.swift` + `LemanaVPNApp.swift` + `SessionTiming.swift`. All prior dirty work is preserved. +**Plan Review Gate:** PRE review passed; implementation and post-review checks completed (see GOAL.md). + +## DNS contract + +- The helper uses fixed system commands and root-owned persistent files. Snapshot stores location, service names, original DNS (empty means DHCP), exact INTERNAL_IP4_DNS, boot identity and owning OpenConnect PID/start identity. It never sources state as code. +- All hook and recovery transactions share native `/usr/bin/lockf -k` in the protected root directory. The helper runs its embedded shell body under the lock, with no public unlocked entry point. The lock releases on process death and survives reboot as an unlocked file. Validate versioned journal data and reject symlink/untrusted state paths. +- Never overwrite an unresolved journal: recover a proven orphan under the same lock, otherwise fail the new hook visibly and retain the journal. A hook may exclude only its verified OpenConnect owner and actual ancestors from the live-process guard; startup excludes nobody. Owner identity is boot plus PID plus process start time. +- Hook connect stores a durable journal before invoking vpnc-script. Observe all enabled network services so interface changes during setup do not defeat capture. Capture only valid DNS output; no heuristic range inference. +- Startup recovery checks actual OpenConnect, openconnect-lite and non-status Lemana connect processes before restoring, and checks again before writes. Missing/failed process evidence blocks mutation. Reused non-VPN PIDs do not block a legitimate old-boot recovery. +- Restore only recorded services in the same network location when current DNS exactly matches the expected VPN list; no-op if already original. If the user changed DNS since the session, preserve it. Keep failed restores for retry. +- Normal hook disconnect preserves custom DNS too: capture the desired value before upstream's unconditional DHCP reset, then restore it only if upstream left empty/expected DNS and no competing tunnel is active. Owner mismatch never consumes another session's journal. +- The disconnect exception requires exact owner and network-location match before upstream invocation. A failed upstream call retains the journal. Tests must exercise custom DNS through upstream's unconditional Empty, partial recovery followed by new connect, location mismatch, and concurrent hook/recovery. +- Snapshotless pre-upgrade leftovers cannot be proven foreign from a 10.x address alone. Automatic repair must skip them and document the limitation, not invent the prior setting. +- CLI startup uses sudo -n and fixed JSON result states. Old/missing helper is detected by a read-only protocol marker, never by executing an old helper with an unknown flag. The app surfaces upgrade/permission/recovery failures and blocks Connect while checking. Recovery never creates a VPN session. + +## Task board and parallel scopes + +1. Root: DNS wrapper/journal/hook implementation, CLI repair/capability/hook args, installer helper update/template, DNS fixture tests. No icon files edited by root during parallel work. +2. Icon agent (explicitly parallel): ONLY `app/Sources/LemanaVPN/VPNIcons.swift`, `LemanaVPNApp.swift`, `SessionTiming.swift`, `tests/icons.py`. Exact approved family from `artifacts/icon-family-v1/draw_icons.py`: 24-grid, 1.75 stroke, neutral 14% body, 60% bottom-up progress fill and colored perimeter; no demo 8h. No VPNManager/install/DNS/README edits. Return packaging instructions to root. +3. Root after icon merge: startup recovery lifecycle/UI messages in manager and menu, installer icon download, docs and full focused regressions. Credentials/auth/reconnect policy remain unchanged. +4. Read-only correctness/safety/maintainability reviewers; fix blockers; run shell checks, new DNS/icons tests, smoke, auth/config/import/menu/logging checks, Swift release build and diff whitespace check. + +## Known limits + +No software can restore a pre-upgrade custom DNS value that was never recorded. Unrecognised root journal or network-location changes are preserved for inspection. Native visual quality and actual reboot/network acceptance remain unproven without a separate live-test request. diff --git a/docs/goals/two-auth-modes/GOAL.md b/docs/goals/two-auth-modes/GOAL.md new file mode 100644 index 0000000..45c8b34 --- /dev/null +++ b/docs/goals/two-auth-modes/GOAL.md @@ -0,0 +1,13 @@ +# Goal: Two Auth Modes + +Use Krypton Execution to execute `docs/goals/two-auth-modes/PLAN.md`. + +Core rules: +- Treat PLAN.md as the source plan. +- Preserve intent, ownership, contract, cutover, evidence, and kill criteria. +- Keep exactly two public modes: `manual-keychain` and `bitwarden-auto`. +- Do not introduce a third first-class user mode; old flags/env may exist only as compatibility shims mapped to one of the two modes. +- Manual-keychain stores only LDAP username/password in macOS Keychain and always leaves OTP manual. +- Bitwarden-auto preserves the old personal Bitwarden + Touch ID + full autofill/submit path. +- Capture acceptance evidence from both checkout source and installed local paths. +- Say "implemented but unproven" if installed-path or launch evidence cannot be captured. diff --git a/docs/goals/two-auth-modes/PLAN.md b/docs/goals/two-auth-modes/PLAN.md new file mode 100644 index 0000000..636d3c7 --- /dev/null +++ b/docs/goals/two-auth-modes/PLAN.md @@ -0,0 +1,201 @@ +# Two Auth Modes Implementation Plan + +**Intent:** Схлопнуть Lemana VPN до двух понятных пользовательских режимов: ручной вход с сохранёнными LDAP login/password в macOS Keychain и старый личный automatic path через Bitwarden + Touch ID + полный autofill/submit. +**Current Behavior:** Checkout уже manual-first, но публичный контракт всё ещё размазан по `manual`, `saved-login`, `saved-totp`, `auto`, совместимым alias-командам и status/menu `available_modes`. Локально установленный `~/bin/vpn-lemanapro.sh` отстаёт от checkout, поэтому старые сборки и приложение могут видеть другую схему. +**Expected Outcome:** Installer, CLI, app menu, README и smoke tests показывают ровно два режима: `manual-keychain` и `bitwarden-auto`. Первый хранит только LDAP username/password в Keychain и всегда оставляет OTP ручным. Второй сохраняет старую рабочую конфигурацию с Bitwarden, Touch ID, permanent 2FA secret, hidden browser, autofill и submit. +**Target-Perspective Output:** Пользователь переустанавливает пакет, выбирает один из двух режимов, видит тот же выбор в `vpn --status` и в LemanaVPN.app. В ручном режиме он может подключиться с подстановкой логина/пароля, каждый раз вводит OTP руками и может обновить логин/пароль из меню. В Bitwarden-режиме работает прежний автоматический путь. +**Truth Owner:** Два repo profile-template файла владеют режимами; `install.sh` выбирает один профиль и пишет активный `~/.config/lemana-vpn/env`; `bin/vpn-lemanapro.sh` исполняет режим; Swift app только читает CLI JSON и запускает CLI. +**Contract Boundary:** Public contract: mode id `manual-keychain|bitwarden-auto`, CLI flags/status JSON/app menu labels. Internal compatibility may still map old flags to a mode, but UI/docs/installer no longer expose four profiles as first-class choices. +**Cutover:** Fresh install defaults to `manual-keychain` and offers `bitwarden-auto` as the old personal advanced mode. Existing env files with `manual`, `saved-login`, `saved-totp`, or `auto` are migrated or normalized to one of the two public modes during install/status. +**Displaced Path:** Displace public `manual`, `saved-login`, `saved-totp`, and `auto` profile matrix. Keep only minimal compatibility aliases where needed, and make them resolve to one of the two modes. +**Value Density:** The smallest high-value slice removes mode ambiguity and stale install drift while preserving the two flows the user actually needs. +**Acceptance Evidence:** Clean temp HOME install output shows only two modes. Source and installed `vpn --status --json` agree on mode/status JSON. Fake launch captures prove manual-keychain uses visible browser, login/password autofill, no TOTP autofill, no submit; bitwarden-auto uses Bitwarden sync, Touch ID when enabled, hidden browser, TOTP autofill, submit. Installed CLI shasum matches checkout and installed app binary contains the updated menu strings. +**Evidence Lane:** Non-live first: shell syntax, smoke tests, Swift build, `git diff --check`, source/installed status JSON and installed binary string checks. Live VPN check only after `vpn --status`, starting with manual-keychain visible flow; skip if connected/connecting unless explicitly approved. +**Kill Criteria:** No installer prompt, README section, app menu, or `available_modes` JSON may present more than two public modes. No fresh install may require Bitwarden. No manual-keychain path may save or require TOTP seed. No bitwarden-auto path may silently degrade into half-configured Keychain-only auto. +**Architecture Slice:** `install.sh`, `bin/vpn-lemanapro.sh`, two new profile-template files, Swift app menu contract, README, smoke tests, installed-path refresh checks. +**Plan Review Gate:** PRE self-review done against Krypton reviewer checklist; external subagent review not run because subagents require an explicit user request in this environment. + +## Короткий План + +🎯 Цель: оставить ровно два рабочих режима установки и подключения: ручной с Keychain login/password + ручной OTP, и старый Bitwarden/Touch ID automatic flow. + +📦 Репозитории: только `/Users/dokril/git/home/lemana-vpn`. + +🧩 Модули: `install.sh`, `bin/vpn-lemanapro.sh`, `app/Sources/LemanaVPN`, `templates/`, `tests/smoke.sh`, `README.md`; installed refresh checks для `~/bin/vpn-lemanapro.sh` и `~/Applications/LemanaVPN.app`. + +🛠 Основные изменения: +- Создать два profile-template файла в `templates/`: `manual-keychain.env` и `bitwarden-auto.env`. +- Перевести installer на выбор только этих двух режимов; убрать публичные вопросы про `saved-login/saved-totp/auto`. +- В CLI ввести public mode `LEMANA_VPN_MODE=manual-keychain|bitwarden-auto` и нормализовать старые env/flags в один из двух режимов. +- Сделать app menu и status JSON двухрежимными: `Подключить`, `Подключить старым автоматическим способом`, `Изменить логин и пароль`. +- Оставить старые flags/aliases только как compatibility shims, без отдельного третьего режима в UI/docs. +- Переписать smoke tests под два режима и добавить installed-path evidence: `shasum`, `strings`, `vpn --status --json`. +- Сжать README до двух сценариев установки и восстановления. + +✅ Проверка: `sh -n install.sh`, `sh -n uninstall.sh`, `bash -n bin/vpn-lemanapro.sh`, `sh -n tests/smoke.sh`, `tests/smoke.sh`, `swift build -c release --package-path app`, `git diff --check`, затем installed checks после `sh install.sh`. + +⚠️ Риски: старые env с `saved-totp`/`auto` могут мигрировать не туда; installed CLI/app могут снова отставать; live auto-flow зависит от Bitwarden/Touch ID и permanent 2FA secret. + +➡️ Следующий шаг: начать с mode contract и двух template-файлов, затем подключить installer/runtime normalization. + +## Architecture Slice + +Files to create: + +- `templates/manual-keychain.env` - source profile for the normal manual mode. +- `templates/bitwarden-auto.env` - source profile for the old personal automatic mode. + +Files to modify: + +- `install.sh` - two-mode wizard, env rendering from templates, migration from old flags/env, final next steps. +- `bin/vpn-lemanapro.sh` - public mode parser, compatibility mapping, status JSON, app menu JSON, runtime env for autofill/click/TOTP. +- `app/Sources/LemanaVPN/VPNManager.swift` - two launch modes, menu labels, status decoding if JSON shape changes. +- `app/Sources/LemanaVPN/LemanaVPNApp.swift` - remove multi-mode rendering that exposes old profiles; keep credential edit action. +- `tests/smoke.sh` - replace four-profile assertions with two-mode assertions plus compatibility tests. +- `README.md` - rewrite mode docs around two supported configurations. +- `docs/goals/manual-first-auth-flow/*` - mark superseded or point to this plan to avoid executing the older four-profile plan. + +Files to avoid: + +- `libexec/lemana-vpn-dns-cleanup` - unrelated to auth mode split. +- `templates/openconnect-lite-config.toml` unless fake launch evidence shows separate openconnect-lite configs are necessary. +- Direct installed `openconnect-lite` source edits; keep using the existing runtime patch path. + +Source of truth: + +- Repo templates define the two modes. +- Active install writes exactly one selected mode into `~/.config/lemana-vpn/env`. +- Keychain stores LDAP password for `manual-keychain`; Bitwarden remains the upstream source for `bitwarden-auto` and syncs into Keychain at runtime. + +Read path: + +- `install.sh` reads selected mode and profile template, writes env. +- `bin/vpn-lemanapro.sh` reads env, normalizes legacy fields, checks required credentials for the selected mode, emits JSON/status, launches `openconnect-lite`. +- Swift app reads only `vpn --status --json` and passes a CLI argument for the chosen mode. + +Write path: + +- `vpn --configure-login` writes or updates username/password only for `manual-keychain`. +- Bitwarden path reads item `LM LDAP`, unlocks through Touch ID/manual master password, then writes password and normalized permanent TOTP secret into Keychain for `bitwarden-auto`. +- Installer never writes the current 6-digit OTP. + +Contract boundary: + +- Public mode ids: `manual-keychain`, `bitwarden-auto`. +- Public status JSON should expose `mode.id`, `mode.label`, `mode.ready`, `mode.setup_hint`, and a maximum of two user actions. +- Compatibility inputs allowed: `--saved-login`, `--manual-full`, `--manual`, `--auto`, old `LEMANA_VPN_AUTH_PROFILE`, old `LEMANA_VPN_CREDENTIAL_SOURCE`. + +Integration points: + +- macOS Keychain service `openconnect-lite`. +- Optional Bitwarden CLI item `LM LDAP`. +- Optional Touch ID helper `~/bin/keychain-fingerprint`. +- `templates/openconnect-lite-config.toml` and runtime autofill patches. +- Swift app JSON contract and installed app binary refresh. + +Migration/cutover: + +- `saved-login` -> `manual-keychain`. +- `manual`/`manual-full` -> `manual-keychain`, but if no saved password exists, status shows setup hint and connection can still offer full manual fallback as diagnostic. +- `saved-totp`/`auto` + `credential_source=bitwarden` -> `bitwarden-auto`. +- `saved-totp`/`auto` + `credential_source=keychain` is no longer a public mode; installer should ask to switch to either `manual-keychain` or `bitwarden-auto`, or keep a hidden compatibility shim for one release with a warning. + +Displaced path: + +- The old four-profile matrix. +- App `available_modes` rendering multiple profile buttons. +- README/installer wording that teaches `saved-login`, `saved-totp`, and `auto` as equal modes. + +Acceptance evidence gate: + +- Fresh install dry-run contains only the two human mode names. +- `tests/smoke.sh` proves both launch profiles and legacy compatibility. +- `~/bin/vpn-lemanapro.sh --status --json` matches source behavior after `sh install.sh`. +- `strings ~/Applications/LemanaVPN.app/Contents/MacOS/LemanaVPN` proves updated menu labels are installed. + +## Tasks + +### Task 1 - Define Two Mode Templates + +Scope: create `templates/manual-keychain.env` and `templates/bitwarden-auto.env`; add a tiny renderer/loader in `install.sh`. + +Expected output: the selected profile writes one active public mode and its derived legacy compatibility vars. + +Verification: `sh install.sh --dry-run --non-interactive --mode manual-keychain` and `--mode bitwarden-auto` show the correct env writes without exposing old profile names. + +Acceptance evidence: dry-run output and rendered temp env contents. + +Parallel: no; this is the source-of-truth base. + +### Task 2 - Normalize Runtime Modes + +Scope: update `bin/vpn-lemanapro.sh` to parse `LEMANA_VPN_MODE`, map old env/flags to the two public modes, and derive autofill/TOTP/submit settings. + +Expected output: manual-keychain uses visible browser, password autofill, TOTP off, submit off; bitwarden-auto uses Bitwarden sync, TOTP on, hidden browser, submit on. + +Verification: fake `openconnect-lite` capture in `tests/smoke.sh`; `bash -n bin/vpn-lemanapro.sh`. + +Acceptance evidence: JSON events and capture files for both modes. + +Parallel: after Task 1 only. + +### Task 3 - Simplify Installer And CLI UX + +Scope: installer questions, flags, usage, aliases, final next steps, and legacy migration warning. + +Expected output: installer asks one question with two choices, configures login/password for manual-keychain, and reserves Bitwarden/Touch ID setup for bitwarden-auto. + +Verification: expect-based interactive smoke and dry-run smoke. + +Acceptance evidence: captured installer transcript with no public `saved-login/saved-totp/auto` wording. + +Parallel: can run after Task 1 while Task 2 is in progress, but integration proof must wait. + +### Task 4 - Update Swift Menu Contract + +Scope: `VPNManager.swift` and `LemanaVPNApp.swift`. + +Expected output: disconnected menu is two-mode aware and does not render old profile buttons. Credential edit remains a Terminal launcher for `vpn --configure-login`. + +Verification: Swift source smoke, `swift build -c release --package-path app`, installed binary `strings` after install. + +Acceptance evidence: menu string checks and build output. + +Parallel: can run after Task 2 JSON shape is decided. + +### Task 5 - Rewrite Docs And Supersede Old Plan + +Scope: `README.md`, `docs/goals/manual-first-auth-flow/PLAN.md`, `docs/goals/manual-first-auth-flow/GOAL.md`. + +Expected output: docs teach only two modes and point the older four-profile plan to this plan. + +Verification: `rg -n "saved-totp|auth_profile=|credential_source=|four-profile|manual-full" README.md docs/goals`. + +Acceptance evidence: only compatibility sections mention old names. + +Parallel: can run after Tasks 1-3 settle final names. + +### Task 6 - Final Verification And Installed Refresh + +Scope: run non-live ladder, install locally, compare installed CLI/app, and optionally perform a live manual check if status is safe. + +Expected output: checkout and installed paths agree; user can run the chosen mode from Terminal and app. + +Verification: `sh -n install.sh`, `sh -n uninstall.sh`, `bash -n bin/vpn-lemanapro.sh`, `sh -n tests/smoke.sh`, `tests/smoke.sh`, `swift build -c release --package-path app`, `git diff --check`, `sh install.sh`, `vpn --status --json`, `shasum bin/vpn-lemanapro.sh ~/bin/vpn-lemanapro.sh`, installed app `strings`. + +Acceptance evidence: command outputs plus a note if live VPN was skipped because status was connected/connecting. + +Parallel: no; final integration gate. + +## PRE Self-Review + +Mode: PRE + +Verdict: aligned + +Findings: + +- minor: "two files" could mean runtime shell modules rather than env templates. Smallest correction: execution should confirm with the user before choosing a different file split, but the current plan makes templates the truth owner because the stated pain is reinstall/config drift. +- minor: legacy `saved-totp` + keychain-only users are not part of the requested two modes. Smallest correction: keep one-release compatibility warning or migration prompt rather than deleting the path blindly. + +Recommended next gate: execute Task 1 and Task 2 together as the contract slice, then run smoke before touching Swift/docs. diff --git a/docs/goals/yandex-key-import/GOAL.md b/docs/goals/yandex-key-import/GOAL.md new file mode 100644 index 0000000..f1fb1fe --- /dev/null +++ b/docs/goals/yandex-key-import/GOAL.md @@ -0,0 +1,3 @@ +# Goal: Import Yandex Key OTP locally + +Use Krypton Execution to execute `docs/goals/yandex-key-import/PLAN.md`. Preserve the two auth modes and previous dirty work. Reuse Keychain/PyOTP, verify the selected record before writes, and keep secrets out of logs. Capture synthetic end-to-end wizard/launch evidence; no real backup, Keychain, GUI or VPN tests are authorized. diff --git a/docs/goals/yandex-key-import/PLAN.md b/docs/goals/yandex-key-import/PLAN.md new file mode 100644 index 0000000..858d33c --- /dev/null +++ b/docs/goals/yandex-key-import/PLAN.md @@ -0,0 +1,45 @@ +# Local Yandex Key OTP Import Implementation Plan + +**Intent:** Import the user's selected VPN OTP from an official local Yandex Key export and generate it on this Mac without Bitwarden. +**Current Behavior:** Keychain/PyOTP and OTP autofill already exist, but manual-keychain disables OTP and the auto mode uses Bitwarden; there is no backup importer. +**Expected Outcome:** Installer and CLI expose a local wizard: choose file and entry, verify the current phone code, save only the selected secret in Keychain and enable local OTP. Existing manual setup remains the default. +**Target-Perspective Output:** A synthetic export imported through the real wizard yields one verified Keychain write and the persisted local OTP flag; a fake client receives shown browser, OTP on, submit off. Cancellation/invalid input yields no writes or launch. +**Truth Owner:** `openconnect-lite` Keychain account `totp/` owns the secret; `env` owns `LEMANA_VPN_LOCAL_OTP`; CLI owns status and launch flags. Python helper owns backup parsing and verified import only. +**Contract Boundary:** New CLI `--import-yandex-key`, installer option/question, optional status metadata. No secret in shell arguments, env, output, errors or logs. Only the helper accesses the selected secret in memory. +**Cutover:** Opt-in `LEMANA_VPN_LOCAL_OTP=1` changes manual-keychain OTP from off to on after verification and persistence. Browser stays visible, submit stays off. Existing bitwarden-auto and full-manual behavior remain. +**Displaced Path:** The unconditional manual-mode OTP-off branch becomes a validated optional setting; no new generator, cloud extractor, third auth mode or alternate Keychain store. +**Value Density:** Reuse existing keyring/PyOTP dependencies and existing runtime patches. One helper next to CLI, installed/uninstalled with it. +**Acceptance Evidence:** Deterministic tests of parsing, real PyOTP RFC fixture verification, fake Keychain writes/rollback, CLI dispatch and fake-client capture; status readiness and installer preservation; full automated regression ladder. +**Evidence Lane:** Temporary homes, synthetic public test secrets and stub Keychain only. No actual user export, Keychain, GUI, live VPN, install or uninstall. +**Kill Criteria:** No unsupported OTP silently accepted; no writes before verification; failed activation restores prior Keychain entry; no OTP enabled by mere presence of a saved seed; full-manual never fills OTP. +**Architecture Slice:** `install.sh` -> installed CLI -> sibling `lemana-vpn-import-yandex.py` via OC Python -> existing Keychain + atomic env update -> CLI status/launch -> Swift status. `uninstall.sh` removes the helper. DNS/reconnect/runtime SSO patches and unrelated dirty work are excluded. +**Plan Review Gate:** Requires PRE review before execution. + +## Input and lifecycle contract + +- Verified plaintext format: JSON array with `name`, `secret`, `techInfo` (OTP URI); primary implementations: [GNOME Authenticator](https://world.pages.gitlab.gnome.org/Authenticator/src/authenticator/backup/yandex.rs.html), [Yandex export help](https://yandex.ru/support/id/ru/authorization/twofa-copy). +- Accept only `otpauth://totp`, SHA1, 6 digits, 30 seconds, valid Base32. Reject duplicate critical parameters, secret mismatch, HOTP/YAOTP and unsupported parameters. Never fetch metadata URLs. Mixed backups may contain unsupported records; validate the selected entry. +- Bound file reading to 4 MiB and entries to 1000; sanitize/cap display names. Require a real terminal at production entry, use hidden input for current phone code, allow EOF/interrupt to cancel without repeated prompts. +- Require saved LDAP username/password first (`vpn --configure-login`). Show destination account and the visible/no-submit behavior. Verify current/adjacent 30-second code locally, then write selected secret and enable manual-keychain/local OTP. Prepare the mode-0600 env replacement before changing Keychain; roll back the old secret if activation fails. Preserve unrelated env settings, no backup copy retained or removed automatically. +- `LEMANA_VPN_LOCAL_OTP` is 0 by default, only 0/1 accepted; invocation environment overrides env file. Reset to 0 in env to return to manual codes while retaining the saved seed. Bitwarden ignores this flag; full-manual ignores it for launch/preflight. +- Status must distinguish local OTP readiness and missing-seed guidance without reading/displaying secrets. Existing older CLI/Swift decoding remains compatible. + +## Ordered tasks + +1. Root implements Python helper and focused tests (`bin/lemana-vpn-import-yandex.py`, `tests/yandex_import.py`). Read-only explorer/review agents validate format/security. Test synthetic success, wrong code/selection, malformed/unsupported input, EOF, secret-safe output, storage/config failures and rollback. +2. Root integrates CLI flag/config, local preflight, status and launch (`bin/vpn-lemanapro.sh`) plus manual readiness decoding (`VPNManager.swift`). Preserve old command/event shapes where unchanged. Add fake-launch/status/no-TTY tests to `tests/smoke.sh` and focused wizard tests. +3. Root integrates installer question/flag and helper packaging/removal (`install.sh`, `uninstall.sh`), documents workflow and limits (`README.md`). Existing unowned-env preservation retains local OTP across updates; add evidence to `tests/configuration.py`. No extra GUI controls. +4. Read-only correctness/maintainability/POST plan review, fix blockers, then final syntax, wizard/config/logging tests, smoke and Swift release build. Main agent owns edits and integration; independent read-only work can run in parallel. + +## Risks + +Wrong OTP type/parameters produces silent login failures; unsupported settings must fail before persistence. Wrong selected account is addressed by explicit selection and phone-code verification. File/Keychain errors must not silently switch modes or replace usable credentials. Real macOS Keychain prompts and live SSO remain unverified without a separate current request. + +## Completed evidence + +- PRE and POST plan/maintainability reviews passed. Security review findings resolved: saved/effective/runtime LDAP binding, strict parameter allowlist, case/whitespace-safe secret masking before label truncation, Keychain readback, and a consistent commit point with interruption handling. +- `tests/yandex_import.py` passes with the existing OC Python. Synthetic RFC TOTP data exercise valid import, mixed exports, unsupported types/parameters, malformed/oversized files, EOF/wrong code, Keychain/config failures, rollback/commit and silent-backend failure. +- Automated PTY drives the actual CLI and sibling helper against a temporary fake Keychain: verified one-account write, unchanged LDAP password, no echoed phone code/secret, persisted setting and ready CLI JSON. Runtime account mismatches and explicit local-OTP override are checked. +- Shell syntax, `tests/smoke.sh`, `tests/configuration.py` (10 checks), `tests/logging.py`, `git diff --check`: PASS. Smoke captures local OTP on, full-manual off, missing seed blocking launch, unchanged Bitwarden flow, installer action/packaging and uninstall removal. +- `swift build -c release --package-path app`: PASS (3.29 s). Restricted run hit compiler cache and nested sandbox restrictions; approved build escalation completed without launching the app. +- No real export, real Keychain writes, real installation, GUI or live VPN acceptance was performed. Abrupt process death/power loss across separate Keychain/filesystem stores remains a documented limitation. diff --git a/install.sh b/install.sh index abb80b6..7e8e8a6 100755 --- a/install.sh +++ b/install.sh @@ -9,25 +9,82 @@ 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}" DNS_CLEANUP="/usr/local/sbin/lemana-vpn-dns-cleanup" +# Read saved scalar settings without executing shell code. Explicit environment wins. +read_saved_settings() { + [ -f "$CONFIG_DIR/env" ] || [ -f "$OC_CONFIG_DIR/config.toml" ] || return 0 + CONFIG_FILE="$CONFIG_DIR/env" OC_CONFIG_FILE="$OC_CONFIG_DIR/config.toml" python3 - <<'PYCONFIG' +import json +import os +import re +import shlex +from pathlib import Path + +keys = ("MODE", "USERNAME", "BW_ITEM", "USE_TOUCHID", "AUTH_PROFILE", "CREDENTIAL_SOURCE", "USE_BITWARDEN", "LOCAL_OTP", "AUTO_SOURCE") +pattern = re.compile(r"(?m)^(?:export[ \t]+)?(LEMANA_VPN_(?:" + "|".join(keys) + r"))=[ \t]*(\"(?:\\[\s\S]|[^\"\\])*\"|'[^']*'|[^\r\n]*)[ \t]*(?:#.*)?$") +values = {} +path = Path(os.environ["CONFIG_FILE"]) +if path.exists(): + for match in pattern.finditer(path.read_text()): + key, raw = match.groups() + if raw.startswith('"'): + value = re.sub(r'\\([$`"\\\n])', lambda m: "" if m[1] == "\n" else m[1], raw[1:-1]) + else: + parts = shlex.split(raw, comments=True) + if len(parts) > 1: + continue + value = parts[0] if parts else "" + values[key] = value + +if not values.get("LEMANA_VPN_USERNAME") and "LEMANA_VPN_USERNAME" not in os.environ: + path = Path(os.environ["OC_CONFIG_FILE"]) + if path.exists(): + section = re.search(r"""(?ms)^[ \t]*\[[ \t]*(?:credentials|"credentials"|'credentials')[ \t]*\][ \t]*(?:#[^\n]*)?(?:\n|\Z)(.*?)(?=^[ \t]*\[|\Z)""", path.read_text()) + match = re.search(r"""(?m)^[ \t]*(?:username|"username"|'username')[ \t]*=[ \t]*("(?:\\.|[^"\\])*"|'[^']*')""", section[1] if section else "") + if match: + raw = match[1] + values["LEMANA_VPN_USERNAME"] = json.loads(raw) if raw.startswith('"') else raw[1:-1] + +# Select auth behavior from one priority layer; saved legacy fields cannot override it. +if "LEMANA_VPN_MODE" not in os.environ and any("LEMANA_VPN_" + key in os.environ for key in ("AUTH_PROFILE", "CREDENTIAL_SOURCE", "USE_BITWARDEN")): + for key in ("MODE", "AUTH_PROFILE", "CREDENTIAL_SOURCE", "USE_BITWARDEN", "LOCAL_OTP"): + values.pop("LEMANA_VPN_" + key, None) +if "LEMANA_VPN_MODE" in os.environ: + values.pop("LEMANA_VPN_LOCAL_OTP", None) +for key, value in values.items(): + if key not in os.environ: + print(key + "=" + shlex.quote(value)) + if key == "LEMANA_VPN_USERNAME": + print("SAVED_USERNAME=" + shlex.quote(value)) +PYCONFIG +} +saved_settings="$(read_saved_settings)" +eval "$saved_settings" USERNAME="${LEMANA_VPN_USERNAME:-}" BW_ITEM="${LEMANA_VPN_BW_ITEM:-LM LDAP}" -CREDENTIAL_SOURCE="${LEMANA_VPN_CREDENTIAL_SOURCE:-none}" +MODE="${LEMANA_VPN_MODE:-}" +LOCAL_OTP="${LEMANA_VPN_LOCAL_OTP:-0}" +AUTO_SOURCE="${LEMANA_VPN_AUTO_SOURCE:-keychain}" +MANUAL_FORCED=0 +CREDENTIAL_SOURCE="${LEMANA_VPN_CREDENTIAL_SOURCE:-}" AUTH_PROFILE="${LEMANA_VPN_AUTH_PROFILE:-manual}" -USE_BITWARDEN=0 -USE_TOUCHID=0 +USE_BITWARDEN="${LEMANA_VPN_USE_BITWARDEN:-0}" +USE_TOUCHID="${LEMANA_VPN_USE_TOUCHID:-0}" INSTALL_SUDOERS=1 INSTALL_ALIASES=1 INSTALL_APP=1 INSTALL_AUTOSTART=1 CONFIGURE_LOGIN=0 CONFIGURE_KEYCHAIN=0 +IMPORT_YANDEX_KEY=0 DRY_RUN=0 FORCE=0 INTERACTIVE=auto BITWARDEN_FORCED=0 +MODE_FORCED=0 CREDENTIAL_SOURCE_FORCED=0 AUTH_PROFILE_FORCED=0 TOUCHID_FORCED=0 +[ "${LEMANA_VPN_USE_TOUCHID+x}" != x ] || TOUCHID_FORCED=1 SUDOERS_FORCED=0 SHELL_FORCED=0 APP_FORCED=0 @@ -81,12 +138,14 @@ Usage: Options: --with-bitwarden Install/use Bitwarden CLI module as an optional credential source --without-bitwarden Do not install/use Bitwarden CLI (default) - --credential-source VALUE Credential source: none, keychain, or bitwarden - --auth-profile VALUE Auth profile: manual, saved-login, saved-totp, or auto + --mode VALUE Profile: manual-keychain, keychain-auto or bitwarden-auto + --credential-source VALUE Legacy credential source: none, keychain, or bitwarden + --auth-profile VALUE Legacy compatibility profile --with-touchid Install/use keychain-fingerprint Touch ID helper with Bitwarden --without-touchid Do not install/use Touch ID helper --configure-login Prompt for LDAP username/password after install --configure-keychain Prompt for LDAP password and permanent 2FA setup code after install + --import-yandex-key Import a local Yandex Key backup after login setup (Terminal required) --username VALUE Corporate LDAP username (otherwise asked on first Terminal connection) --bw-item VALUE Bitwarden item name (default: LM LDAP) --raw-base-url URL Raw file base URL for curl installs @@ -105,50 +164,107 @@ Options: Examples: sh install.sh + sh install.sh --mode manual-keychain --configure-login + sh install.sh --mode bitwarden-auto sh install.sh --configure-login - sh install.sh --credential-source keychain --auth-profile saved-totp --configure-keychain sh install.sh --without-touchid USAGE } +apply_mode_defaults() { + case "$MODE" in + manual-keychain) + LOCAL_OTP=0 + AUTH_PROFILE="saved-login" + CREDENTIAL_SOURCE="keychain" + USE_BITWARDEN=0 + USE_TOUCHID=0 + ;; + keychain-auto) + AUTH_PROFILE="auto" + CREDENTIAL_SOURCE="keychain" + USE_BITWARDEN=0 + USE_TOUCHID=0 + LOCAL_OTP=1 + AUTO_SOURCE=keychain + ;; + bitwarden-auto) + LOCAL_OTP=0 + AUTO_SOURCE=bitwarden + AUTH_PROFILE="auto" + CREDENTIAL_SOURCE="bitwarden" + USE_BITWARDEN=1 + if [ "$TOUCHID_FORCED" -eq 0 ]; then + USE_TOUCHID=1 + fi + ;; + *) + echo "--mode requires manual-keychain, keychain-auto or bitwarden-auto" >&2 + exit 1 + ;; + esac +} + +normalize_mode_from_legacy() { + if [ -z "$MODE" ]; then + [ -n "$CREDENTIAL_SOURCE" ] || { [ "$USE_BITWARDEN" -ne 1 ] || CREDENTIAL_SOURCE=bitwarden; } + case "$CREDENTIAL_SOURCE:$AUTH_PROFILE" in + bitwarden:*|*:auto) + MODE="bitwarden-auto" + ;; + *) + MODE="manual-keychain" + ;; + esac + fi + if [ "$MODE" = manual-keychain ] && [ "$LOCAL_OTP" = 1 ] && [ "$MANUAL_FORCED" -eq 0 ]; then + MODE=keychain-auto + fi + apply_mode_defaults +} + while [ "$#" -gt 0 ]; do case "$1" in --with-bitwarden) - CREDENTIAL_SOURCE="bitwarden" - USE_BITWARDEN=1 + MODE="bitwarden-auto" + MODE_FORCED=1 + apply_mode_defaults BITWARDEN_FORCED=1 CREDENTIAL_SOURCE_FORCED=1 - if [ "$AUTH_PROFILE_FORCED" -eq 0 ] && [ "$AUTH_PROFILE" = "manual" ]; then - AUTH_PROFILE="saved-totp" - fi ;; --without-bitwarden) - if [ "$CREDENTIAL_SOURCE" = "bitwarden" ]; then - CREDENTIAL_SOURCE="none" - fi + MANUAL_FORCED=1 + MODE="manual-keychain" + MODE_FORCED=1 + apply_mode_defaults USE_BITWARDEN=0 USE_TOUCHID=0 BITWARDEN_FORCED=1 ;; + --mode) + shift + [ "$#" -gt 0 ] || { echo "--mode requires manual-keychain, keychain-auto or bitwarden-auto" >&2; exit 1; } + MODE="$1" + [ "$MODE" != manual-keychain ] || MANUAL_FORCED=1 + MODE_FORCED=1 + apply_mode_defaults + ;; --credential-source) shift [ "$#" -gt 0 ] || { echo "--credential-source requires none, keychain, or bitwarden" >&2; exit 1; } CREDENTIAL_SOURCE="$1" CREDENTIAL_SOURCE_FORCED=1 case "$CREDENTIAL_SOURCE" in - none) - USE_BITWARDEN=0 - USE_TOUCHID=0 - ;; - bitwarden) - USE_BITWARDEN=1 - if [ "$AUTH_PROFILE_FORCED" -eq 0 ] && [ "$AUTH_PROFILE" = "manual" ]; then - AUTH_PROFILE="saved-totp" + none|keychain) + if [ "$MODE_FORCED" -eq 0 ]; then + MODE="manual-keychain" + MANUAL_FORCED=1 fi ;; - keychain) - USE_BITWARDEN=0 - USE_TOUCHID=0 + bitwarden) + if [ "$MODE_FORCED" -eq 0 ]; then + MODE="bitwarden-auto" + fi ;; *) echo "--credential-source requires none, keychain, or bitwarden" >&2 @@ -162,7 +278,17 @@ while [ "$#" -gt 0 ]; do AUTH_PROFILE="$1" AUTH_PROFILE_FORCED=1 case "$AUTH_PROFILE" in - manual|saved-login|saved-totp|auto) ;; + manual|saved-login) + if [ "$MODE_FORCED" -eq 0 ]; then + MODE="manual-keychain" + MANUAL_FORCED=1 + fi + ;; + saved-totp|auto) + if [ "$MODE_FORCED" -eq 0 ]; then + MODE="bitwarden-auto" + fi + ;; *) echo "--auth-profile requires manual, saved-login, saved-totp, or auto" >&2 exit 1 @@ -178,30 +304,28 @@ while [ "$#" -gt 0 ]; do TOUCHID_FORCED=1 ;; --configure-login) + MANUAL_FORCED=1 + if [ "$MODE_FORCED" -eq 0 ]; then + MODE="manual-keychain" + fi CONFIGURE_LOGIN=1 CONFIGURE_LOGIN_FORCED=1 CONFIGURE_KEYCHAIN=0 - if [ "$AUTH_PROFILE_FORCED" -eq 0 ]; then - AUTH_PROFILE="saved-login" - fi - if [ "$CREDENTIAL_SOURCE_FORCED" -eq 0 ]; then - CREDENTIAL_SOURCE="keychain" - USE_BITWARDEN=0 - USE_TOUCHID=0 + ;; + --import-yandex-key) + IMPORT_YANDEX_KEY=1 + if [ "$MODE_FORCED" -eq 0 ]; then + MODE="keychain-auto" fi + MODE_FORCED=1 ;; --configure-keychain) + if [ "$MODE_FORCED" -eq 0 ]; then + MODE="bitwarden-auto" + fi CONFIGURE_KEYCHAIN=1 CONFIGURE_LOGIN=0 CONFIGURE_KEYCHAIN_FORCED=1 - if [ "$AUTH_PROFILE_FORCED" -eq 0 ]; then - AUTH_PROFILE="saved-totp" - fi - if [ "$CREDENTIAL_SOURCE_FORCED" -eq 0 ]; then - CREDENTIAL_SOURCE="keychain" - USE_BITWARDEN=0 - USE_TOUCHID=0 - fi ;; --username) shift @@ -247,10 +371,10 @@ while [ "$#" -gt 0 ]; do --interactive) INTERACTIVE=1 ;; --non-interactive) INTERACTIVE=0 ;; --minimal) - CREDENTIAL_SOURCE="none" - AUTH_PROFILE="manual" - USE_BITWARDEN=0 - USE_TOUCHID=0 + MANUAL_FORCED=1 + MODE="manual-keychain" + MODE_FORCED=1 + apply_mode_defaults BITWARDEN_FORCED=1 CREDENTIAL_SOURCE_FORCED=1 AUTH_PROFILE_FORCED=1 @@ -271,6 +395,9 @@ while [ "$#" -gt 0 ]; do shift done +[ -z "$MODE" ] || MODE_FORCED=1 +normalize_mode_from_legacy + log() { printf '%s\n' "$*" } @@ -326,8 +453,13 @@ need_cmd() { command -v "$1" >/dev/null 2>&1 || die "Command not found: $1" } +tty_available() { + { [ -r /dev/tty ] && [ -w /dev/tty ]; } || return 1 + { : <> /dev/tty; } 2>/dev/null +} + has_tty() { - { [ -r /dev/tty ] && [ -w /dev/tty ]; } || [ -t 0 ] + tty_available || [ -t 0 ] } interactive_enabled() { @@ -340,7 +472,7 @@ interactive_enabled() { } prompt_printf() { - if [ -w /dev/tty ]; then + if tty_available; then printf "$@" > /dev/tty else printf "$@" @@ -348,13 +480,19 @@ prompt_printf() { } prompt_read_answer() { - if [ -r /dev/tty ]; then + if tty_available; then IFS= read -r answer < /dev/tty || answer="" else IFS= read -r answer || answer="" fi } +preserve_existing_username() { + if [ -n "${SAVED_USERNAME:-}" ] && [ "$USERNAME" = "$SAVED_USERNAME" ]; then + log_info "Preserving existing LDAP username from previous config" + fi +} + yes_no() { prompt="$1" default_answer="$2" @@ -385,119 +523,60 @@ yes_no() { print_install_intro() { log_step "Lemana VPN установит приложение для подключения к корпоративному VPN" - log_detail "По умолчанию ничего не сохраняется: при подключении откроется окно входа, а логин, пароль и одноразовый код вводятся вручную." - log_detail "Дополнительные удобства можно включить сейчас или позже." -} - -choose_advanced_signin_interactive() { - while :; do - prompt_printf '\n' - prompt_printf '%sАвтоматический вход требует сохранённых данных.%s\n' "$C_BOLD" "$C_RESET" - prompt_printf ' Автоматический вход работает только если на Mac сохранены корпоративный пароль\n' - prompt_printf ' и постоянный код настройки 2FA. Это не текущие 6 цифр из приложения.\n\n' - prompt_printf ' 1) Вернуться к ручному режиму\n' - prompt_printf ' 2) Сохранить пароль и постоянный код 2FA в macOS Keychain\n' - prompt_printf ' 3) Взять пароль и код 2FA из Bitwarden\n' - prompt_printf '%sВыбор [1/2/3, Enter=1]:%s ' "$C_BOLD" "$C_RESET" - - prompt_read_answer - case "$answer" in - ""|1) - AUTH_PROFILE=manual - CREDENTIAL_SOURCE=none - USE_BITWARDEN=0 - USE_TOUCHID=0 - CONFIGURE_LOGIN=0 - CONFIGURE_KEYCHAIN=0 - ;; - 2) - AUTH_PROFILE=saved-totp - CREDENTIAL_SOURCE=keychain - USE_BITWARDEN=0 - USE_TOUCHID=0 - CONFIGURE_LOGIN=0 - CONFIGURE_KEYCHAIN=1 - ;; - 3) - AUTH_PROFILE=saved-totp - CREDENTIAL_SOURCE=bitwarden - USE_BITWARDEN=1 - CONFIGURE_LOGIN=0 - CONFIGURE_KEYCHAIN=0 - ;; - *) - prompt_printf 'Введите 1, 2 или 3. Если не уверены, нажмите Enter.\n' - continue - ;; - esac - break - done + log_detail "Есть два режима: ручной ввод кода и автоматический вход. Для автоматического входа выберите ключ на Mac или Bitwarden." + log_detail "Ключ из Яндекс Ключа можно импортировать отдельно, без Bitwarden." } choose_auth_profile_interactive() { log_step "Выбираю режим подключения" - log_detail "Если не уверены, просто нажмите Enter: будет ручной режим без сохранения паролей." + log_detail "Если не уверены, просто нажмите Enter: будет ручной режим с сохранением логина и пароля." while :; do prompt_printf '\n' - prompt_printf '%sКак подключаться по умолчанию?%s\n' "$C_BOLD" "$C_RESET" - prompt_printf ' 1) Вводить всё вручную (рекомендуется)\n' - prompt_printf ' Откроется окно входа. Вы сами введёте логин, пароль и одноразовый код.\n\n' - prompt_printf ' 2) Запомнить логин и пароль на этом Mac\n' - prompt_printf ' При входе логин и пароль подставятся сами. Одноразовый код вы введёте вручную.\n\n' - prompt_printf ' 3) Настроить автоматический вход\n' - prompt_printf ' Нужно заранее сохранить пароль и постоянный код настройки 2FA.\n' - prompt_printf '%sВыбор [1/2/3, Enter=1]:%s ' "$C_BOLD" "$C_RESET" + prompt_printf '%sКакой режим использовать?%s\n' "$C_BOLD" "$C_RESET" + prompt_printf ' 1) Ручной вход: запомнить логин и пароль на этом Mac (рекомендуется)\n' + prompt_printf ' Логин и пароль подставятся из macOS Keychain. Одноразовый код вводится руками каждый раз.\n\n' + prompt_printf ' 2) Автоматический вход\n' + prompt_printf ' Пароль и код подставляются автоматически, форма отправляется без ручного ввода.\n' + prompt_printf '%sВыбор [1/2, Enter=1]:%s ' "$C_BOLD" "$C_RESET" prompt_read_answer case "$answer" in ""|1) - AUTH_PROFILE=manual - CREDENTIAL_SOURCE=none - USE_BITWARDEN=0 - USE_TOUCHID=0 - CONFIGURE_LOGIN=0 - CONFIGURE_KEYCHAIN=0 - if yes_no "Сохранить логин и пароль в macOS Keychain для подстановки при входе?" n; then - AUTH_PROFILE=saved-login - CREDENTIAL_SOURCE=keychain - USE_BITWARDEN=0 - USE_TOUCHID=0 - CONFIGURE_LOGIN=1 - CONFIGURE_KEYCHAIN=0 - fi - ;; - 2) - AUTH_PROFILE=saved-login - CREDENTIAL_SOURCE=keychain - USE_BITWARDEN=0 - USE_TOUCHID=0 + MANUAL_FORCED=1 + MODE=manual-keychain + apply_mode_defaults CONFIGURE_LOGIN=1 CONFIGURE_KEYCHAIN=0 ;; - 3) - choose_advanced_signin_interactive + 2) + prompt_printf 'Источник данных: 1) Ключ на этом Mac, 2) Bitwarden [1/2, Enter=1]: ' + prompt_read_answer + case "$answer" in + ""|1) MODE=keychain-auto; CONFIGURE_LOGIN=1 ;; + 2) MODE=bitwarden-auto; CONFIGURE_LOGIN=0 ;; + *) prompt_printf 'Введите 1 или 2.\n'; continue ;; + esac + apply_mode_defaults + CONFIGURE_KEYCHAIN=0 ;; *) - prompt_printf 'Введите 1, 2 или 3. Если не уверены, нажмите Enter.\n' + prompt_printf 'Введите 1 или 2. Если не уверены, нажмите Enter.\n' continue ;; esac break done - case "$AUTH_PROFILE" in - manual) - log_info "Режим подключения: ручной ввод логина, пароля и одноразового кода" + case "$MODE" in + manual-keychain) + log_info "Режим подключения: логин и пароль в macOS Keychain, одноразовый код вручную" ;; - saved-login) - log_info "Режим подключения: логин и пароль будут сохранены в macOS Keychain, одноразовый код вводится вручную" + keychain-auto) + log_info "Режим подключения: автоматический, ключ на этом Mac" ;; - saved-totp) - log_info "Режим подключения: сохранённые данные будут подставляться в форму входа" - ;; - auto) - log_info "Режим подключения: автоматический вход включается только через явный auto-запуск" + bitwarden-auto) + log_info "Режим подключения: автоматический, Bitwarden" ;; esac } @@ -579,26 +658,25 @@ choose_modules() { log_info "Interactive prompts: on" log_detail "Установщик проведёт по понятному выбору режима входа; флаги командной строки имеют приоритет." - if [ "$AUTH_PROFILE_FORCED" -eq 0 ] && [ "$CREDENTIAL_SOURCE_FORCED" -eq 0 ]; then + if [ "$MODE_FORCED" -eq 0 ] && [ "$AUTH_PROFILE_FORCED" -eq 0 ] && [ "$CREDENTIAL_SOURCE_FORCED" -eq 0 ]; then choose_auth_profile_interactive fi if [ "$CREDENTIAL_SOURCE" = "bitwarden" ] && [ "$BITWARDEN_FORCED" -eq 0 ] && ! command -v bw >/dev/null 2>&1; then if yes_no "Bitwarden не найден на этом Mac. Установить его сейчас?" n; then - CREDENTIAL_SOURCE=bitwarden - USE_BITWARDEN=1 + MODE=bitwarden-auto + apply_mode_defaults else - AUTH_PROFILE=manual - CREDENTIAL_SOURCE=none - USE_BITWARDEN=0 - USE_TOUCHID=0 + MODE=manual-keychain + apply_mode_defaults + CONFIGURE_LOGIN=1 fi fi if [ "$TOUCHID_FORCED" -eq 0 ]; then if [ "$USE_BITWARDEN" -eq 1 ]; then if ! [ -x "$INSTALL_BIN_DIR/keychain-fingerprint" ]; then - if yes_no "Разрешить Touch ID для открытия Bitwarden?" n; then + if yes_no "Разрешить Touch ID для открытия Bitwarden?" y; then USE_TOUCHID=1 else USE_TOUCHID=0 @@ -644,7 +722,7 @@ choose_modules() { fi fi - if [ "$CONFIGURE_LOGIN_FORCED" -eq 0 ] && [ "$AUTH_PROFILE" = "saved-login" ] && [ "$CONFIGURE_LOGIN" -eq 0 ]; then + if [ "$CONFIGURE_LOGIN_FORCED" -eq 0 ] && [ "$MODE" != "bitwarden-auto" ] && [ "$CONFIGURE_LOGIN" -eq 0 ]; then if ! keychain_has openconnect-lite "$USERNAME"; then if yes_no "Запомнить логин и пароль в macOS Keychain после установки?" y; then CONFIGURE_LOGIN=1 @@ -652,13 +730,20 @@ choose_modules() { fi fi - if [ "$CONFIGURE_KEYCHAIN_FORCED" -eq 0 ] && [ "$AUTH_PROFILE" = "saved-totp" ] && [ "$CREDENTIAL_SOURCE" = "keychain" ] && [ "$CONFIGURE_KEYCHAIN" -eq 0 ]; then + if [ "$CONFIGURE_KEYCHAIN_FORCED" -eq 0 ] && [ "$MODE" = "bitwarden-auto" ] && [ "$CREDENTIAL_SOURCE" = "keychain" ] && [ "$CONFIGURE_KEYCHAIN" -eq 0 ]; then if ! keychain_has openconnect-lite "$USERNAME" || ! keychain_has openconnect-lite "totp/$USERNAME"; then if yes_no "Сохранить пароль и постоянный код настройки 2FA в macOS Keychain после установки?" y; then CONFIGURE_KEYCHAIN=1 fi fi fi + if [ "$MODE" != "bitwarden-auto" ] && [ "$IMPORT_YANDEX_KEY" -eq 0 ] && ! keychain_has openconnect-lite "totp/$USERNAME"; then + import_default=n + [ "$MODE" != keychain-auto ] || import_default=y + if yes_no "Импортировать код из Яндекс Ключа и включить автоматический вход?" "$import_default"; then + IMPORT_YANDEX_KEY=1 + fi + fi } script_dir() { @@ -703,6 +788,37 @@ write_file() { printf '%s\n' "$content" > "$dst" } +render_template_file() { + src="$1" + dst="$2" + if [ "$DRY_RUN" -eq 1 ]; then + printf '+ render %s -> %s\n' "$src" "$dst" + return 0 + fi + USERNAME="$USERNAME" BW_ITEM="$BW_ITEM" DNS_CLEANUP="$DNS_CLEANUP" USE_TOUCHID="$USE_TOUCHID" AUTO_SOURCE="$AUTO_SOURCE" \ + CONFIG_FILE="$CONFIG_DIR/env" python3 - "$src" "$dst" <<'PYCONFIG' +import os +import re +import sys +from pathlib import Path + + +def shell_value(value): + return value.replace("\\", "\\\\").replace('"', '\\"').replace("$", "\\$").replace("`", "\\`") + + +rendered = Path(sys.argv[1]).read_text() +rendered = re.sub(r"\{\{(USERNAME|BW_ITEM|DNS_CLEANUP|USE_TOUCHID|AUTO_SOURCE)\}\}", lambda m: shell_value(os.environ[m[1]]), rendered) +keys = re.findall(r"(?m)^(LEMANA_VPN_\w+)=", rendered) +existing = Path(os.environ["CONFIG_FILE"]) +kept = "" +if existing.exists(): + pattern = r"(?m)^(?:export[ \t]+)?(?:" + "|".join(keys) + r")=[ \t]*(?:\"(?:\\[\s\S]|[^\"\\])*\"|'[^']*'|[^\r\n]*)[ \t]*\n?" + kept = re.sub(pattern, "", existing.read_text()).rstrip() +Path(sys.argv[2]).write_text((kept + "\n" if kept else "") + rendered) +PYCONFIG +} + install_homebrew_packages() { need_cmd brew @@ -761,6 +877,9 @@ install_cli() { run install -m 755 "$tmp/vpn-lemanapro.sh" "$INSTALL_BIN_DIR/vpn-lemanapro.sh" log_ok "CLI installed: $INSTALL_BIN_DIR/vpn-lemanapro.sh" + download_file "bin/lemana-vpn-import-yandex.py" "$tmp/lemana-vpn-import-yandex.py" + run install -m 644 "$tmp/lemana-vpn-import-yandex.py" "$INSTALL_BIN_DIR/lemana-vpn-import-yandex.py" + download_file "uninstall.sh" "$tmp/uninstall.sh" run install -m 755 "$tmp/uninstall.sh" "$INSTALL_BIN_DIR/uninstall-lemana-vpn.sh" log_ok "Uninstall helper installed: $INSTALL_BIN_DIR/uninstall-lemana-vpn.sh" @@ -768,6 +887,7 @@ install_cli() { install_config() { tmp="$1" + mode_template="$tmp/$MODE.env" log_step "Записываю конфигурацию" log_detail "Здесь сохраняются выбранный режим входа, LDAP username если он задан, и профиль openconnect-lite для Keycloak SSO." @@ -777,18 +897,35 @@ install_config() { if [ "$DRY_RUN" -eq 1 ]; then printf '+ render %s/config.toml\n' "$OC_CONFIG_DIR" else - sed "s/{{USERNAME}}/$USERNAME/g" "$tmp/openconnect-lite-config.toml" > "$OC_CONFIG_DIR/config.toml" - chmod 600 "$OC_CONFIG_DIR/config.toml" + USERNAME="$USERNAME" python3 - "$OC_CONFIG_DIR/config.toml" "$tmp/openconnect-lite-config.toml" "$tmp/config.toml" <<'PYCONFIG' +import json +import os +import re +import sys +from pathlib import Path + +existing, template, destination = map(Path, sys.argv[1:]) +text = (existing if existing.exists() else template).read_text() +username = "username = " + json.dumps(os.environ["USERNAME"], ensure_ascii=False) +section = re.search(r"""(?ms)^[ \t]*\[[ \t]*(?:credentials|"credentials"|'credentials')[ \t]*\][ \t]*(?:#[^\n]*)?(?:\n|\Z)(.*?)(?=^[ \t]*\[|\Z)""", text) +if section: + body = section[1] + username_key = r"""(?m)^[ \t]*(?:username|"username"|'username')[ \t]*=""" + if re.search(username_key, body): + body = re.sub(username_key + r".*$", lambda _: username, body) + else: + body = username + "\n" + body + prefix = text[:section.start(1)] + text = prefix + ("" if prefix.endswith("\n") else "\n") + body + text[section.end(1):] +else: + text = text.rstrip() + "\n\n[credentials]\n" + username + "\n" +destination.write_text(text) +PYCONFIG fi - env_content="LEMANA_VPN_USERNAME=\"$USERNAME\" -LEMANA_VPN_AUTH_PROFILE=\"$AUTH_PROFILE\" -LEMANA_VPN_CREDENTIAL_SOURCE=\"$CREDENTIAL_SOURCE\" -LEMANA_VPN_BW_ITEM=\"$BW_ITEM\" -LEMANA_VPN_USE_BITWARDEN=\"$USE_BITWARDEN\" -LEMANA_VPN_USE_TOUCHID=\"$USE_TOUCHID\" -LEMANA_VPN_DNS_CLEANUP=\"$DNS_CLEANUP\"" - write_file "$tmp/env" "$env_content" + download_file "templates/$MODE.env" "$mode_template" + render_template_file "$mode_template" "$tmp/env" + run install -m 600 "$tmp/config.toml" "$OC_CONFIG_DIR/config.toml" run install -m 600 "$tmp/env" "$CONFIG_DIR/env" log_ok "Config installed: $CONFIG_DIR/env" } @@ -798,7 +935,7 @@ install_dns_cleanup() { dns_cleanup_dir="$(dirname "$DNS_CLEANUP")" log_step "Устанавливаю DNS cleanup wrapper" - log_detail "Wrapper сбрасывает только похожие на корпоративные 10.x DNS после аварийного завершения VPN." + log_detail "Wrapper сохраняет прежние DNS и восстанавливает изменения VPN после отключения или перезагрузки." log_detail "macOS может запросить sudo-пароль для записи в $dns_cleanup_dir." download_file "libexec/lemana-vpn-dns-cleanup" "$tmp/lemana-vpn-dns-cleanup" @@ -814,6 +951,11 @@ install_sudoers() { return 0 fi + if [ -f /etc/sudoers.d/lemana-vpn-openconnect ] && [ -f /etc/sudoers.d/lemana-vpn-dns ] && [ "$FORCE" -eq 0 ]; then + log_ok "Sudoers rules already installed" + return 0 + fi + log_step "Настраиваю sudoers" log_detail "Это убирает повторный sudo-пароль при подключении, но разрешает только openconnect и DNS cleanup wrapper." @@ -881,6 +1023,9 @@ install_menu_bar_app() { download_file "app/Package.swift" "$app_src/Package.swift" download_file "app/Sources/LemanaVPN/LemanaVPNApp.swift" "$app_src/Sources/LemanaVPN/LemanaVPNApp.swift" download_file "app/Sources/LemanaVPN/VPNManager.swift" "$app_src/Sources/LemanaVPN/VPNManager.swift" + download_file "app/Sources/LemanaVPN/BoundedLog.swift" "$app_src/Sources/LemanaVPN/BoundedLog.swift" + download_file "app/Sources/LemanaVPN/SessionTiming.swift" "$app_src/Sources/LemanaVPN/SessionTiming.swift" + download_file "app/Sources/LemanaVPN/VPNIcons.swift" "$app_src/Sources/LemanaVPN/VPNIcons.swift" log_info "Building LemanaVPN.app" run swift build -c release --package-path "$app_src" @@ -994,7 +1139,8 @@ install_shell_aliases() { zshrc="$HOME/.zshrc" tmp="$1" log_step "Обновляю shell aliases" - log_detail "Алиасы vpn, vpn-auto, vpn-manual, vpn-manual-full, vpn-debug и vpn-fix-dns добавляются идемпотентным блоком в ~/.zshrc." + log_detail "Основные алиасы vpn, vpn-auto, vpn-debug и vpn-fix-dns добавляются идемпотентным блоком в ~/.zshrc." + log_detail "vpn-manual и vpn-manual-full остаются только как совместимые fallback-команды." [ -f "$zshrc" ] || run touch "$zshrc" @@ -1011,7 +1157,7 @@ vpn-auto() { "$INSTALL_BIN_DIR/vpn-lemanapro.sh" --auto "\$@"; } vpn-manual() { "$INSTALL_BIN_DIR/vpn-lemanapro.sh" --manual "\$@"; } vpn-manual-full() { "$INSTALL_BIN_DIR/vpn-lemanapro.sh" --manual-full "\$@"; } vpn-debug() { "$INSTALL_BIN_DIR/vpn-lemanapro.sh" --debug "\$@"; } -vpn-fix-dns() { sudo "$DNS_CLEANUP"; } +vpn-fix-dns() { "$INSTALL_BIN_DIR/vpn-lemanapro.sh" --repair-dns; } # <<< lemana-vpn EOF @@ -1036,6 +1182,10 @@ maybe_login_bitwarden() { log_skip "Bitwarden не выбран; пропускаю Bitwarden login." return 0 fi + if [ "$DRY_RUN" -eq 1 ]; then + printf '+ bw status # check Bitwarden login state\n' + return 0 + fi if ! command -v bw >/dev/null 2>&1; then log_warn "Bitwarden CLI enabled but bw not found." return 0 @@ -1055,12 +1205,11 @@ maybe_login_bitwarden() { } auth_profile_label() { - case "$AUTH_PROFILE" in - manual) printf 'ручной ввод без сохранения паролей' ;; - saved-login) printf 'сохранить логин и пароль, одноразовый код вводить вручную' ;; - saved-totp) printf 'подставлять сохранённые данные в окно входа' ;; - auto) printf 'автоматический вход только при явном запуске' ;; - *) printf '%s' "$AUTH_PROFILE" ;; + case "$MODE" in + manual-keychain) printf 'ручной вход: логин и пароль в Keychain, одноразовый код вручную' ;; + keychain-auto) printf 'автоматический вход: ключ на этом Mac' ;; + bitwarden-auto) printf 'автоматический вход: Bitwarden' ;; + *) printf '%s' "$MODE" ;; esac } @@ -1068,23 +1217,12 @@ print_final_next_steps() { log "" log_ok "Готово." log_info "Open a new shell or run: exec zsh" - case "$AUTH_PROFILE" in - manual) - log_info "Как подключиться: откройте LemanaVPN.app и нажмите \"Подключить\", или выполните: vpn" - log_detail "Откроется окно входа. Введите корпоративный логин, пароль и одноразовый код вручную." - ;; - saved-login) - log_info "Как подключиться: Lemana VPN подставит логин и пароль, одноразовый код введите вручную." - log_detail "Команда подключения: vpn" - ;; - saved-totp) - log_info "Как подключиться: Lemana VPN подставит сохранённые данные в видимое окно входа." - log_detail "Для полностью автоматического запуска используйте явно: vpn-auto" - ;; - auto) - log_info "Автоматический вход включён явно. Если он не сработает, используйте ручной режим: vpn --manual-full" - ;; - esac + if [ "$IMPORT_YANDEX_KEY" -eq 1 ] || [ "$MODE" != manual-keychain ]; then + log_info "Как подключиться: автоматический вход командой vpn или кнопкой \"Подключить\"." + else + log_info "Как подключиться: Lemana VPN подставит логин и пароль, одноразовый код введите вручную." + fi + log_detail "Способ входа можно изменить в меню приложения." log_info "Status: vpn --status" if [ "$INSTALL_APP" -eq 1 ]; then log_info "App: open '$APP_DIR'" @@ -1097,7 +1235,14 @@ main() { tmp="$(mktemp -d)" trap 'rm -rf "$tmp"' EXIT INT TERM + preserve_existing_username choose_modules + if [ "$IMPORT_YANDEX_KEY" -eq 1 ]; then + [ "$MODE" != "bitwarden-auto" ] || die "Импорт Яндекс Ключа используется с локальным ключом, без Bitwarden." + if [ -z "$USERNAME" ] || ! keychain_has openconnect-lite "$USERNAME"; then + CONFIGURE_LOGIN=1 + fi + fi log_step "Начинаю установку Lemana VPN" log_detail "Повторный запуск безопасен: файлы обновляются идемпотентно, существующие credentials не перезаписываются." @@ -1105,7 +1250,7 @@ main() { log_info "Выбран режим: $(auth_profile_label)" log_detail "Bitwarden и Touch ID будут установлены только если они выбраны явно." else - log_info "Modules: auth_profile=$AUTH_PROFILE credential_source=$CREDENTIAL_SOURCE bitwarden=$USE_BITWARDEN touchid=$USE_TOUCHID sudoers=$INSTALL_SUDOERS shell=$INSTALL_ALIASES app=$INSTALL_APP autostart=$INSTALL_AUTOSTART" + log_info "Modules: mode=$MODE bitwarden=$USE_BITWARDEN touchid=$USE_TOUCHID sudoers=$INSTALL_SUDOERS shell=$INSTALL_ALIASES app=$INSTALL_APP autostart=$INSTALL_AUTOSTART" fi install_homebrew_packages @@ -1123,7 +1268,7 @@ main() { if [ "$CONFIGURE_LOGIN" -eq 1 ]; then log_step "Записываю логин и пароль в macOS Keychain" - log_detail "Будет запрошен корпоративный LDAP-пароль. Одноразовый код при подключении останется ручным." + log_detail "Будет запрошен корпоративный LDAP-пароль; настройка одноразового кода выполняется отдельно." run "$INSTALL_BIN_DIR/vpn-lemanapro.sh" --configure-login elif [ "$CONFIGURE_KEYCHAIN" -eq 1 ]; then log_step "Записываю credentials в macOS Keychain" @@ -1131,6 +1276,12 @@ main() { run "$INSTALL_BIN_DIR/vpn-lemanapro.sh" --configure-keychain fi + if [ "$IMPORT_YANDEX_KEY" -eq 1 ]; then + log_step "Импортирую код из Яндекс Ключа" + log_detail "Выберите локальный файл и запись VPN, затем подтвердите её текущим кодом с телефона." + run "$INSTALL_BIN_DIR/vpn-lemanapro.sh" --import-yandex-key + fi + print_final_next_steps } diff --git a/libexec/lemana-vpn-dns-cleanup b/libexec/lemana-vpn-dns-cleanup index fe1a7ff..d564e2f 100755 --- a/libexec/lemana-vpn-dns-cleanup +++ b/libexec/lemana-vpn-dns-cleanup @@ -1,23 +1,383 @@ #!/bin/sh -set -eu +# LEMANA_DNS_PROTOCOL=2 +# LEMANA_SESSION_PROTOCOL=1 +# LEMANA_RECONNECT_PROTOCOL=1 +set -efu +PATH=/usr/bin:/bin:/usr/sbin:/sbin +LC_ALL=C +export PATH LC_ALL +umask 077 -SERVICES="${LEMANA_VPN_DNS_SERVICES:-Wi-Fi -USB 10/100/1000 LAN -Ethernet}" +fail() { printf '%s\n' "$1" >&2; exit 1; } +case "${1:---recover}:$#" in --recover:0|--recover:1|--vpnc:1|--vpnc:2|--vpnc:3|--begin:3|--stop:2|--restart:3|--recover-session:2) ;; *) fail 'Unsupported helper arguments.' ;; esac +[ "$(/usr/bin/id -u)" = 0 ] || fail 'DNS helper requires root.' +STATE=/var/db/lemana-vpn-dns +[ ! -L "$STATE" ] || fail 'Unsafe DNS state directory.' +/bin/mkdir -p "$STATE" +[ "$(/usr/bin/stat -f '%u:%Lp' "$STATE")" = '0:700' ] || fail 'Unsafe DNS state permissions.' +[ ! -L "$STATE/lock" ] || fail 'Unsafe DNS lock.' +# A kernel lock releases after a crash; -k keeps all callers on the same inode. +exec /usr/bin/lockf -k -t 15 "$STATE/lock" /bin/sh -s -- "${1:---recover}" "${2:-}" "${3:-}" <<'LOCKED' +set -efu +PATH=/usr/bin:/bin:/usr/sbin:/sbin +LC_ALL=C +export PATH LC_ALL +umask 077 +STATE=/var/db/lemana-vpn-dns +JOURNAL="$STATE/journal" +NEXT="$STATE/next" +SESSION="$STATE/session" +SESSION_NEXT="$STATE/session-next" +TAB="$(printf '\t')" +mode=$1 +token=$2 +caller=$3 +exclude=' ' +changed=0 +fail() { printf '%s\n' "$1" >&2; exit 1; } +trap '/bin/rm -f "$NEXT" "$SESSION_NEXT"' EXIT -printf '%s\n' "$SERVICES" | while IFS= read -r service; do - [ -n "$service" ] || continue - - dns="$(/usr/sbin/networksetup -getdnsservers "$service" 2>/dev/null || true)" - printf '%s\n' "$dns" | grep -q '^10\.' || continue - - /usr/sbin/networksetup -setdnsservers "$service" empty >/dev/null 2>&1 || { - printf 'Failed to reset DNS for %s\n' "$service" >&2 - exit 1 - } - printf 'DNS reset for %s\n' "$service" -done - -/usr/bin/dscacheutil -flushcache >/dev/null 2>&1 || true -/usr/bin/killall -HUP mDNSResponder >/dev/null 2>&1 || true +# Never evaluate journal content or use it as a command/path. +normalize_dns() { + /usr/bin/awk ' + function valid(s, n,a,i) { + if (s ~ /:/) return s ~ /^[0-9a-fA-F:]+(%[a-zA-Z0-9_.-]+)?$/ + n=split(s,a,"."); if (n!=4) return 0 + for(i=1;i<=4;i++) if(a[i]!~/^[0-9]+$/ || a[i]>255) return 0 + return 1 + } + { for(i=1;i<=NF;i++) { if(!valid($i)) exit 1; out=out (out?" ":"") $i } } + END { if(out!="") print out } + ' +} +read_dns() { + value=$(/usr/sbin/networksetup -getdnsservers "$1" 2>/dev/null) || return 1 + case "$value" in "There aren't any DNS Servers set on "*) printf 'empty\n' ;; *) + [ -n "$value" ] || return 1 + printf '%s\n' "$value" | normalize_dns + esac +} +valid_dns() { + [ "$1" = empty ] || [ "$(printf '%s\n' "$1" | normalize_dns)" = "$1" ] +} +location() { + /usr/sbin/networksetup -getcurrentlocation 2>/dev/null +} +single_line() { + case "$1" in ''|*"$TAB"*|*' +'*) return 1 ;; esac +} +processes() { + table=$(/bin/ps -axww -o pid=,ppid=,lstart=,command= 2>/dev/null) || fail 'Cannot verify running VPN processes.' + printf '%s\n' "$table" | /usr/bin/awk 'NF<8 || $1!~/^[0-9]+$/ || $2!~/^[0-9]+$/ {exit 1} END {if(NR==0) exit 1}' || fail 'Cannot verify running VPN processes.' +} +process_field() { + printf '%s\n' "$table" | /usr/bin/awk -v pid="$1" -v field="$2" '$1==pid {if(field=="start") print $3,$4,$5,$6,$7; else print $2; exit}' +} +active() { + processes + if printf '%s\n' "$table" | /usr/bin/awk -v skip="$exclude" ' + { parent[$1]=$2; command=""; for(i=8;i<=NF;i++) command=command " " $i } + command ~ /(^|[ \/])openconnect(-lite)?([[:space:]]|$)/ {engine[$1]=1} + command ~ /(^|[ \/])vpn-lemanapro[.]sh([[:space:]]|$)/ && command !~ / --(status|help|repair-dns|patch-only|configure-login|configure-keychain|import-yandex-key)([[:space:]]|$)| --(set-auth|stop-session|restart-session)=/ {cli[$1]=1} + END { + for(pid in parent) { + if(index(skip," " pid " ")) continue + # Bash pipeline/progress children retain the parent CLI argv. + if(engine[pid] || (cli[pid] && !cli[parent[pid]])) found=1 + } + exit !found + }'; then return 0 + else + result_code=$? + [ "$result_code" = 1 ] || fail 'Cannot verify running VPN processes.' + return 1 + fi +} +process_uid() { + /bin/ps -p "$1" -o uid= | /usr/bin/awk 'NF==1 && $1~/^[0-9]+$/ {print $1}' +} +valid_token() { + [ "${#1}" = 36 ] || return 1 + case "$1" in *[!a-f0-9-]*) return 1 ;; esac +} +descendant() { + ancestor=$1; depth=0 + while [ "$ancestor" -gt 1 ] && [ "$depth" -lt 64 ]; do + [ "$ancestor" != "$2" ] || return 0 + ancestor=$(process_field "$ancestor" parent) + case "$ancestor" in ''|*[!0-9]*) return 1 ;; esac + depth=$((depth + 1)) + done + return 1 +} +load_session() { + [ ! -L "$SESSION" ] && [ -f "$SESSION" ] || fail 'Missing or unsafe VPN session record.' + [ "$(/usr/bin/stat -f '%u:%Lp' "$SESSION")" = '0:600' ] || fail 'Unsafe VPN session permissions.' + IFS="$TAB" read -r sv sb st su sc ss se ses stopped engine_attempt < "$SESSION" || fail 'Invalid VPN session record.' + case "$sv" in 1) engine_attempt=- ;; 2) [ "$engine_attempt" = - ] || valid_token "$engine_attempt" || fail 'Invalid engine attempt.' ;; *) fail 'Unsupported VPN session record.' ;; esac + valid_token "$st" && single_line "$sb" && single_line "$ss" && single_line "$ses" || fail 'Invalid VPN session identity.' + case "$su:$sc:$se:$stopped" in *[!0-9:]*|:*|*::*|*:) fail 'Invalid VPN session identity.' ;; esac + [ "$sc" -gt 1 ] && [ "$stopped" -le 1 ] || fail 'Invalid VPN session identity.' + /usr/bin/awk -F '\t' '($1==1 && NF!=9) || ($1==2 && NF!=10) {exit 1} END {if(NR!=1) exit 1}' "$SESSION" || fail 'Invalid VPN session record.' +} +save_session() { + [ ! -L "$SESSION_NEXT" ] || fail 'Unsafe VPN session temporary file.' + printf '2\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n' "$sb" "$st" "$su" "$sc" "$ss" "$se" "$ses" "$stopped" "$engine_attempt" > "$SESSION_NEXT" + /bin/mv -f "$SESSION_NEXT" "$SESSION" +} +session_operation() { + valid_token "$token" || fail 'Invalid session token.' + case "${SUDO_UID:-}" in ''|*[!0-9]*) fail 'Missing requesting user.' ;; esac + processes + boot_now=$(/usr/sbin/sysctl -n kern.bootsessionuuid) || fail 'Cannot verify boot identity.' + if [ "$mode" = --begin ]; then + case "$caller" in ''|*[!0-9]*) fail 'Invalid session caller.' ;; esac + [ "$caller" -gt 1 ] && descendant "$$" "$caller" || fail 'Session caller is not an ancestor.' + [ "$(process_uid "$caller")" = "$SUDO_UID" ] || fail 'Session caller belongs to another user.' + if [ -e "$SESSION" ] || [ -L "$SESSION" ]; then + load_session + if [ "$sb" = "$boot_now" ] && { [ "$(process_field "$sc" start)" = "$ss" ] || [ "$(process_field "$se" start)" = "$ses" ]; }; then + fail 'A registered VPN session is still running.' + fi + fi + sb=$boot_now; st=$token; su=$SUDO_UID; sc=$caller; ss=$(process_field "$caller" start); se=0; ses=-; stopped=0; engine_attempt=- + single_line "$ss" || fail 'Cannot verify session start.' + save_session + printf 'ready\n' + return + fi + load_session + [ "$st:$su:$sb" = "$token:$SUDO_UID:$boot_now" ] || fail 'VPN session identity does not match.' + if [ "$mode" = --recover-session ]; then + [ "$(process_field "$sc" start)" = "$ss" ] && descendant "$$" "$sc" || fail 'Recovery caller is not the registered CLI.' + # Only the idle CLI is exempt; every VPN/SSO engine still blocks recovery. + exclude=" $sc " + recover + if [ "$stopped" = 1 ] && [ "$result" != active ]; then result=cancelled; fi + printf '%s\n' "$result" + return + fi + if [ "$mode" = --restart ]; then + valid_token "$caller" || fail 'Invalid expected engine attempt.' + if [ "$stopped" = 1 ]; then printf 'cancelled\n'; return; fi + # A delayed health request must not stop a replacement tunnel. + if [ "$engine_attempt" != "$caller" ]; then printf 'stale\n'; return; fi + fi + # Commit cancellation before signaling: a late pre-init hook must not start a tunnel. + if [ "$mode" = --stop ]; then stopped=1; save_session; fi + if [ "$(process_field "$se" start)" = "$ses" ]; then + [ "$(process_uid "$se")" = 0 ] || fail 'Recorded VPN owner changed.' + processes + if [ "$(process_field "$se" start)" = "$ses" ]; then + printf '%s\n' "$table" | /usr/bin/awk -v pid="$se" '$1==pid {n=split($8,a,"/"); if(a[n]=="openconnect") ok=1} END {exit !ok}' || fail 'Recorded VPN executable changed.' + /bin/kill -TERM "$se" || fail 'Could not stop the recorded VPN process.' + fi + elif [ "$mode" = --stop ] && [ "$(process_field "$sc" start)" = "$ss" ] && [ "$(process_uid "$sc")" = "$su" ]; then + # Before the tunnel exists, terminate only this user's authentication children. + candidates=$(printf '%s\n' "$table" | /usr/bin/awk '{print $1}') + targets='' + for candidate in $candidates; do + if descendant "$candidate" "$sc" && [ "$(process_uid "$candidate")" = "$su" ]; then + targets="$targets$candidate$TAB$(process_field "$candidate" start) +" + fi + done + printf '%s' "$targets" | while IFS="$TAB" read -r candidate started; do + processes + [ "$(process_field "$candidate" start)" = "$started" ] || continue + [ "$(process_uid "$candidate")" = "$su" ] || fail 'Session child owner changed.' + /bin/kill -TERM "$candidate" || fail 'Could not stop the authentication process.' + done + fi + # Do not wait under the DNS lock: the engine's disconnect hook needs it. + printf 'stopping\n' +} +owner() { + case "${VPNPID:-}" in ''|*[!0-9]*) fail 'Missing VPN process identity.' ;; esac + [ "$VPNPID" -gt 1 ] || fail 'Invalid VPN process identity.' + processes + printf '%s\n' "$table" | /usr/bin/awk -v pid="$VPNPID" '$1==pid {n=split($8,a,"/"); if(a[n]=="openconnect") ok=1} END {exit !ok}' || fail 'Cannot verify VPN process owner.' + current_start=$(process_field "$VPNPID" start) + current_boot=$(/usr/sbin/sysctl -n kern.bootsessionuuid 2>/dev/null) || fail 'Cannot verify boot identity.' + single_line "$current_boot" || fail 'Cannot verify boot identity.' + # Verify the supplied owner is really an ancestor of this hook. + ancestor=$$; depth=0; found=0 + while [ "$ancestor" -gt 1 ] && [ "$depth" -lt 64 ]; do + [ "$ancestor" != "$VPNPID" ] || found=1 + ancestor=$(process_field "$ancestor" parent) + case "$ancestor" in ''|*[!0-9]*) fail 'Cannot verify VPN process ancestry.' ;; esac + depth=$((depth + 1)) + done + [ "$found" = 1 ] || fail 'VPN owner is not the hook parent.' + exclude=' '; ancestor=$VPNPID; depth=0 + while [ "$ancestor" -gt 1 ] && [ "$depth" -lt 64 ]; do + exclude="$exclude$ancestor " + ancestor=$(process_field "$ancestor" parent) + case "$ancestor" in ''|*[!0-9]*) fail 'Cannot verify VPN process ancestry.' ;; esac + depth=$((depth + 1)) + done + [ "$ancestor" -le 1 ] || fail 'Cannot verify VPN process ancestry.' +} +load_journal() { + [ ! -L "$JOURNAL" ] && [ -f "$JOURNAL" ] || fail 'Unsafe DNS journal.' + [ "$(/usr/bin/stat -f '%u:%Lp' "$JOURNAL")" = '0:600' ] || fail 'Unsafe DNS journal permissions.' + IFS="$TAB" read -r version boot pid start place phase expected < "$JOURNAL" || fail 'Invalid DNS journal.' + [ "$version" = 2 ] || fail 'Unsupported DNS journal.' + single_line "$boot" && single_line "$start" && single_line "$place" || fail 'Invalid DNS journal identity.' + case "$pid" in ''|*[!0-9]*) fail 'Invalid DNS journal identity.' ;; esac + case "$phase" in connected|disconnecting) ;; *) fail 'Invalid DNS journal phase.' ;; esac + old_ifs=$IFS; IFS=';' + for list in $expected; do valid_dns "$list" && [ "$list" != empty ] || fail 'Invalid DNS journal addresses.'; done + IFS=$old_ifs + [ -n "$expected" ] || fail 'Invalid DNS journal addresses.' + /usr/bin/awk -F '\t' 'NR==1 {if(NF!=7) exit 1; next} NF!=4 || $1!="service" || $2=="" || seen[$2]++ {exit 1} END {if(NR<2) exit 1}' "$JOURNAL" || fail 'Invalid DNS journal records.' + while IFS="$TAB" read -r tag service before wanted; do + [ "$tag" = service ] || continue + valid_dns "$before" && valid_dns "$wanted" || fail 'Invalid DNS journal addresses.' + done < "$JOURNAL" +} +write_header() { + printf '2\t%s\t%s\t%s\t%s\t%s\t%s\n' "$boot" "$pid" "$start" "$place" "$phase" "$expected" +} +commit() { + /bin/mv -f "$NEXT" "$JOURNAL" + /bin/sync +} +expected_dns() { + case ";$expected;" in *";$1;"*) return 0 ;; *) return 1 ;; esac +} +set_dns() { + # The parser only permits address tokens; glob expansion is disabled. + old_ifs=$IFS; IFS=' '; set -- "$1" $2; IFS=$old_ifs + /usr/sbin/networksetup -setdnsservers "$@" >/dev/null 2>&1 || fail 'Could not restore recorded DNS.' + changed=1 +} +recover() { + if active; then result=active; return; fi + if [ ! -e "$JOURNAL" ] && [ ! -L "$JOURNAL" ]; then result=no_snapshot; return; fi + load_journal + current_place=$(location) || fail 'Cannot read network location.' + [ "$current_place" = "$place" ] || fail 'Saved DNS belongs to another network location.' + while IFS="$TAB" read -r tag service before wanted; do + [ "$tag" = service ] || continue + current=$(read_dns "$service") || fail 'Cannot read recorded network service DNS.' + target=$before + [ "$phase" != disconnecting ] || target=$wanted + [ "$current" != "$target" ] || continue + if expected_dns "$current" || { [ "$phase" = disconnecting ] && [ "$current" = empty ]; }; then + if active; then result=active; return; fi + [ "$(location)" = "$place" ] || fail 'Network location changed during DNS recovery.' + set_dns "$service" "$target" + [ "$(read_dns "$service")" = "$target" ] || fail 'DNS restoration could not be verified.' + fi + done < "$JOURNAL" + /bin/rm -f "$JOURNAL" + if [ "$changed" = 1 ]; then + /usr/bin/dscacheutil -flushcache >/dev/null 2>&1 || true + /usr/bin/killall -HUP mDNSResponder >/dev/null 2>&1 || true + result=restored + else result=unchanged + fi +} +capture_services() { + services=$(/usr/sbin/networksetup -listallnetworkservices 2>/dev/null) || fail 'Cannot list network services.' + printf '%s\n' "$services" | /usr/bin/sed '1d' | while IFS= read -r service; do + case "$service" in ''|\**) continue ;; esac + single_line "$service" || fail 'Unsupported network service name.' + if SERVICE_NAME="$service" /usr/bin/awk -F '\t' '$1=="service" && $2==ENVIRON["SERVICE_NAME"] {found=1} END {exit !found}' "$NEXT"; then continue; fi + before=$(read_dns "$service") || fail 'Cannot capture original DNS.' + printf 'service\t%s\t%s\t%s\n' "$service" "$before" "$before" >> "$NEXT" + done +} +stock() { + if [ -x /opt/homebrew/etc/vpnc/vpnc-script ]; then + /bin/sh /opt/homebrew/etc/vpnc/vpnc-script + elif [ -x /usr/local/etc/vpnc/vpnc-script ]; then + /bin/sh /usr/local/etc/vpnc/vpnc-script + else fail 'The installed vpnc-script is missing.' + fi +} +case "$mode" in --begin|--stop|--restart|--recover-session) session_operation; exit 0 ;; esac +if [ "$mode" = --recover ]; then + recover + printf '%s\n' "$result" + exit 0 +fi +owner +if [ -n "$token" ]; then + load_session + [ "$st:$sb" = "$token:$current_boot" ] || fail 'VPN hook belongs to another session.' + if [ "${reason:-}" != disconnect ]; then + [ "$stopped" = 0 ] || fail 'VPN session was cancelled.' + [ "$(process_field "$sc" start)" = "$ss" ] && descendant "$VPNPID" "$sc" || fail 'VPN engine is not a session child.' + [ "$(process_uid "$VPNPID")" = 0 ] || fail 'VPN engine requires root.' + if [ "$se" != 0 ] && [ "$se:$ses" != "$VPNPID:$current_start" ] && [ "$(process_field "$se" start)" = "$ses" ]; then + fail 'Another engine is still running in this session.' + fi + engine_attempt=${caller:--} + [ "$engine_attempt" = - ] || valid_token "$engine_attempt" || fail 'Invalid engine attempt.' + se=$VPNPID; ses=$current_start; save_session + else + [ "$se:$ses" = "$VPNPID:$current_start" ] || fail 'VPN disconnect belongs to another engine.' + fi +fi +case "${reason:-}" in + pre-init|attempt-reconnect) stock; exit $? ;; + connect|reconnect) + incoming=$(printf '%s\n' "${INTERNAL_IP4_DNS:-}" | normalize_dns) || fail 'Invalid VPN DNS addresses.' + if active; then fail 'Another VPN connection is active.'; fi + current_place=$(location) || fail 'Cannot read network location.' + single_line "$current_place" || fail 'Invalid network location.' + if [ -e "$JOURNAL" ] || [ -L "$JOURNAL" ]; then + load_journal + if [ "$boot:$pid:$start" != "$current_boot:$VPNPID:$current_start" ] || [ "$phase" != connected ]; then + recover + [ ! -e "$JOURNAL" ] || fail 'Previous DNS recovery is incomplete.' + else + [ "$place" = "$current_place" ] || fail 'Saved DNS belongs to another network location.' + fi + fi + if [ -z "$incoming" ]; then stock; exit $?; fi + if [ -e "$JOURNAL" ]; then + expected_dns "$incoming" || expected="$expected;$incoming" + write_header > "$NEXT" + /usr/bin/sed '1d' "$JOURNAL" >> "$NEXT" + else + boot=$current_boot; pid=$VPNPID; start=$current_start; place=$current_place; phase=connected; expected=$incoming + write_header > "$NEXT" + fi + capture_services + [ "$(/usr/bin/wc -l < "$NEXT")" -gt 1 ] || fail 'No enabled network services to record.' + commit + load_journal + stock || fail 'VPN network setup failed; DNS journal retained.' + ;; + disconnect) + if [ ! -e "$JOURNAL" ] && [ ! -L "$JOURNAL" ]; then stock; exit $?; fi + load_journal + [ "$boot:$pid:$start" = "$current_boot:$VPNPID:$current_start" ] || fail 'DNS journal belongs to another VPN session.' + [ "$(location)" = "$place" ] || fail 'Saved DNS belongs to another network location.' + if active; then fail 'Another VPN connection is active.'; fi + previous_phase=$phase + phase=disconnecting + write_header > "$NEXT" + while IFS="$TAB" read -r tag service before wanted; do + [ "$tag" = service ] || continue + if [ "$previous_phase" = connected ]; then + current=$(read_dns "$service") || fail 'Cannot read recorded network service DNS.' + wanted=$current + if expected_dns "$current"; then wanted=$before; fi + fi + printf 'service\t%s\t%s\t%s\n' "$service" "$before" "$wanted" >> "$NEXT" + done < "$JOURNAL" + capture_services + commit + stock || fail 'VPN network cleanup failed; DNS journal retained.' + recover + [ "$result" != active ] || fail 'DNS recovery deferred while another VPN is active.' + ;; + *) fail 'Unsupported VPN hook reason.' ;; +esac +LOCKED diff --git a/templates/bitwarden-auto.env b/templates/bitwarden-auto.env new file mode 100644 index 0000000..f273244 --- /dev/null +++ b/templates/bitwarden-auto.env @@ -0,0 +1,10 @@ +LEMANA_VPN_MODE="bitwarden-auto" +LEMANA_VPN_USERNAME="{{USERNAME}}" +LEMANA_VPN_AUTH_PROFILE="auto" +LEMANA_VPN_CREDENTIAL_SOURCE="bitwarden" +LEMANA_VPN_BW_ITEM="{{BW_ITEM}}" +LEMANA_VPN_USE_BITWARDEN="1" +LEMANA_VPN_USE_TOUCHID="{{USE_TOUCHID}}" +LEMANA_VPN_LOCAL_OTP="0" +LEMANA_VPN_AUTO_SOURCE="bitwarden" +LEMANA_VPN_DNS_CLEANUP="{{DNS_CLEANUP}}" diff --git a/templates/keychain-auto.env b/templates/keychain-auto.env new file mode 100644 index 0000000..453a32d --- /dev/null +++ b/templates/keychain-auto.env @@ -0,0 +1,10 @@ +LEMANA_VPN_MODE="keychain-auto" +LEMANA_VPN_USERNAME="{{USERNAME}}" +LEMANA_VPN_AUTH_PROFILE="auto" +LEMANA_VPN_CREDENTIAL_SOURCE="keychain" +LEMANA_VPN_BW_ITEM="{{BW_ITEM}}" +LEMANA_VPN_USE_BITWARDEN="0" +LEMANA_VPN_USE_TOUCHID="0" +LEMANA_VPN_LOCAL_OTP="1" +LEMANA_VPN_AUTO_SOURCE="keychain" +LEMANA_VPN_DNS_CLEANUP="{{DNS_CLEANUP}}" diff --git a/templates/manual-keychain.env b/templates/manual-keychain.env new file mode 100644 index 0000000..b056d4c --- /dev/null +++ b/templates/manual-keychain.env @@ -0,0 +1,10 @@ +LEMANA_VPN_MODE="manual-keychain" +LEMANA_VPN_USERNAME="{{USERNAME}}" +LEMANA_VPN_AUTH_PROFILE="saved-login" +LEMANA_VPN_CREDENTIAL_SOURCE="keychain" +LEMANA_VPN_BW_ITEM="{{BW_ITEM}}" +LEMANA_VPN_USE_BITWARDEN="0" +LEMANA_VPN_USE_TOUCHID="0" +LEMANA_VPN_LOCAL_OTP="0" +LEMANA_VPN_AUTO_SOURCE="{{AUTO_SOURCE}}" +LEMANA_VPN_DNS_CLEANUP="{{DNS_CLEANUP}}" diff --git a/templates/openconnect-lite-config.toml b/templates/openconnect-lite-config.toml index 21f7ebf..59deea4 100644 --- a/templates/openconnect-lite-config.toml +++ b/templates/openconnect-lite-config.toml @@ -1,4 +1,4 @@ -on_disconnect = "sudo /usr/local/sbin/lemana-vpn-dns-cleanup >/dev/null 2>&1 || true" +on_disconnect = "sudo -n /usr/local/sbin/lemana-vpn-dns-cleanup --recover >/dev/null 2>&1 || true" [default_profile] address = "vpn.lemanapro.ru" @@ -29,4 +29,3 @@ fill = "totp" [[auto_fill_rules."https://employee.auth.lemanapro.ru/*"]] selector = "input[type=submit], button[type=submit], #kc-login" action = "click" - diff --git a/tests/auth_retry.py b/tests/auth_retry.py new file mode 100644 index 0000000..4c235a1 --- /dev/null +++ b/tests/auth_retry.py @@ -0,0 +1,123 @@ +#!/usr/bin/env python3 +"""Patch a disposable engine and execute its actual autofill JS without Qt/browser.""" +import ast +import json +import os +from pathlib import Path +import subprocess +import sys +import tempfile +import tomllib +from types import SimpleNamespace + +ROOT = Path(__file__).resolve().parents[1] +SMOKE = (ROOT/'tests/smoke.sh').read_text() +with tempfile.TemporaryDirectory(prefix='lemana-auth-retry-') as temporary: + folder = Path(temporary) + for name in ('webengine', 'authenticator'): + fixture = SMOKE.split('cat > "$fake_'+name+'" <<\'PY\'\n', 1)[1].split('\nPY\n', 1)[0] + (folder/(name+'.py')).write_text(fixture) + env = {key:value for key,value in os.environ.items() if not key.startswith(('LEMANA_VPN_', 'OPENCONNECT_LITE_'))} + env.update(HOME=temporary, LEMANA_VPN_WEBENGINE_PROCESS=str(folder/'webengine.py'), + LEMANA_VPN_AUTHENTICATOR=str(folder/'authenticator.py'), LEMANA_VPN_OC_PYTHON=sys.executable, + LEMANA_VPN_PATCH_BACKUP_DIR=str(folder/'backups')) + command = ['bash', str(ROOT/'bin/vpn-lemanapro.sh'), '--patch-only'] + subprocess.run(command, env=env, check=True, capture_output=True) + patched = (folder/'webengine.py').read_text() + subprocess.run(command, env=env, check=True, capture_output=True) + assert patched == (folder/'webengine.py').read_text(), 'Patch must be idempotent' + compile(patched, '', 'exec') + tree = ast.parse(patched) + selectors = next(n for n in tree.body if isinstance(n, ast.FunctionDef) and n.name == 'get_selectors') + template = next(n.args[0] for n in ast.walk(tree) if isinstance(n, ast.Call) + and isinstance(n.func, ast.Attribute) and n.func.attr == 'setSourceCode') + profile = tomllib.loads((ROOT/'templates/openconnect-lite-config.toml').read_text()) + url_pattern, rule_data = next(iter(profile['auto_fill_rules'].items())) + rules = [SimpleNamespace(selector=r['selector'], action=r.get('action'), fill=r.get('fill')) for r in rule_data] + messages, exits, delegated = [], [], [] + class BasePage: + def javaScriptConsoleMessage(self, *args): delegated.append(args) + logger = SimpleNamespace(warning=lambda *args, **kwargs: messages.append(args)) + fake_os = SimpleNamespace(environ={}) + namespace = dict(os=fake_os, json=json, logger=logger, QWebEnginePage=BasePage, + QApplication=SimpleNamespace(instance=lambda: SimpleNamespace(exit=exits.append)), + credentials=SimpleNamespace(username='test-user', password='test-password', totp='123456'), + rules=rules, url_pattern=url_pattern, + js_regex_str=json.dumps('^'+url_pattern.replace('.', '\\.').replace('*', '.*')+'$')) + callback = next(n for n in tree.body if isinstance(n, ast.ClassDef) and n.name == 'LemanaVPNPage') + exec(compile(ast.Module(body=[selectors, callback], type_ignores=[]), '', 'exec'), namespace) + page = namespace['LemanaVPNPage']() + page.javaScriptConsoleMessage(1, 'LEMANA_VPN_AUTH_REJECTED', 0, 'test') + assert exits == [77] and messages == [('LEMANA_VPN_AUTH_REJECTED',)] + fake_os.environ['LEMANA_VPN_AUTOFILL_CLICK'] = '0' + page.javaScriptConsoleMessage(1, 'LEMANA_VPN_AUTH_REJECTED', 0, 'test') + assert exits == [77] and len(delegated) == 1 + scripts = {} + for name, click, attempt in [('auto', '1', 'attempt-one'), ('fresh', '1', 'attempt-two'), ('manual', '0', 'attempt-one')]: + fake_os.environ.update(LEMANA_VPN_AUTOFILL_CLICK=click, LEMANA_VPN_AUTH_ATTEMPT=attempt, + LEMANA_VPN_AUTOFILL_TOTP='0' if name == 'manual' else '1') + scripts[name] = eval(compile(ast.Expression(template), '

Pns{>{E=^uY3kxF&# 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%0A3~M_ z*&9@z2biT&>cNUFf4Va*#bD?;wMW1lM7ae8QSJDG8?&6%JYATZYAtqWWbn&GKXXWGwfqY= z=4spOw(4pLX#3u&YkNaq)03lS44T1)j`K0`kniuTj`h^}pTPb@y9+J=euY$X zfU)K)Ccxwgpc6`hsZlP@DIhfZ;uPJuXc^Jph6X2nWV-sDpDV-rx*mB&CVd44^eXs%OQ536HPYK1-?kPv0v-zglyBU$CM$#{_FeBEMVDEL>$Djg2%PNLrk+ATgd&1!+;dDDdB3np)kHRzU;W~)|n^F?;>6#cWfXk%uU zOBdw~PB-6wXz`jbWR-I)i z0|2hOn{3;-rnKHss!0Vj*Bka@0|jT&!kjZ(^PYc zDI!TdH!Dk-H7J36px8fv`FTM>fm5Qz$kx^|E2&?iNNFx`UQ+(` zbsl3f{WtG(b92-5qbC3P)R zHMk=rF(5n~&{|Cdx%${mino>3<%oZN2-AVR$9ND7%s|;ozp8TkhzAuxujgZm0v$uC zv<2N$W?y=ufHL!^SnD7)Rb5AO^IRqct^fXjtV2Yo@z+B*NSLi?YH@OMGI&7uxoz7Q z@VHQjn;e8`pOHe;UeZ5f8YRW1xwjCZ*OHihZXzdi7@`rAwa`E%=&HJ*sA!B>GEawIv7Z(o~>wAA0 zP%kAVOF6|Rx-yL@wS;2*8N^xH(J(+0L?CT`Gdp~|^cy*Yxj9s{(MU&tdm!O}H%0_+ zo@Lo&Yjf0=mp5yEZD=5n`bDgbW(NUAj_nQ#m=u>iM$M`EqaCqO;o-;V4^RC3a~9ql z!0v_RWHK_+lOVS=`;07#knSaLk^qyH<6m;LyOK*W0;|dr)N#R$W;O zfAQklqUFG^FLB!O%8D`X({p5`rHk#xUim6!0uD2}WzbpZQmLfZ6Jx3x^+vR8&&*Ko z;NXzP#zMjicaA)yq}5>1iKbczTTQ0_mNVmJ}#Yb7w3PhNm!!ak88L zjp99N*JVDw76Pe@%fr`vQJAeDYO3KH6@z3jM{WH9*5FF)L3r-pY0dOHoj`h*fPe|d zM_#yFLwvXzY-oModc4bC3QntQi@zzE^31BMzMpqqv==K$MY-g6=$7B96RU;xzEOIu zhd<;8JTPFUEp>@o7D3pz6|*;k$BP-%1J zoyqkwIy$qzr|&~cYRdYV8S#$HDltkud|)rotI&uEsiukAkFTCtFwgX|RTh3siBL!L@$h72XFG+=DmjKcX>I2deL?fg zZG)1Q_UOjH1-H!-Rm8+oFfVD#Y%TrGQ?32HtC#qTVI}|O$x>{11M^&p{%yCv9YdBiPR4oYz%rn z>n-^k4>x8_ev&BJSg)6&KXlx2T5j0KU~ACvEy^b4c*bSo2{Cp2bs5F?d5V_H1Kd_T zb#$~nsQmnx+Ha)*YX!DwKipK_n7N+OUwKMC{MtR5?5rGX>G2=qoq01~D1}NJb<*Mm z=4kfpR$FZRNeve^^Tr&ckG za3QNtao)evbeh9GPo}v0fjYr>V2gU%?sC`F50(-6AdP3aeuKdsf#WbixV)O0;9N4d zVmH>_{7%EH-k*sn@qK#w)Q3C2L6Ixz&WLC1_i3oE8qd@(}G zrM(w|X5D<1>%!*fbMRhqa}P1s1u>L}NIEof+Tu{sEwFnwo9P#Wu8jkL72Yojd0kJ3 z8ub>l#2pafngW2DjhDCIhf|dEmlO{7k-^q%t%Y%7_W-?Ofn71W!4lQme)0a5F8(Jy z>KgfWOZNPXx)^2M^tB0`G&2$3^h9r}6A6D}*qQqN{QLmPU2A($%lnvx48uxhg(Fd_ z#)*Q7Q6eeZYq>D$>ne5$qx#%a5{$W5UJmtqoZeO5NsjZ2jb*Z;fV_yID^CPduFefd zxya`tf8GA^1tFnLkDzoBxPtHW_>({SOoP^_2Nqbh_ZL5qJzn6A$F$qSKie@hYf`b#P zDjTn|?8#2KY;rxC)8pRjdAA=8AldsVXIvgl$z7JN4%Yr|VQ$fG|K~i$9FRC36TN%c zCH9m!>79vn5e7+D*LB1#y-P`fy~H{D?p28MWD9mnTSv~9;c+MRi@CFN4Zgvmv8t!P zqJ9Hq^W_=czZ`;p)3BFCSWn#l-#-w zOe-hD1T=!{*RLb-SWnE_U}L>U_ov54D5?^(`Zn3`*x>W9*J`eb$LDBSAltI4WQ}vK zsL+F|H8t2c{*4P}h+`Y;Ry}Deq8q(F%X3AdkwR8Aqm(>bZIErn;IaJX)kSY#pMabY zkl<}$I3&2Gv#j|d>Asn}_60;+RFT_CBRLiT%-$rV1qaSf&X0vbi$#m0hlSr#c>Rta-TBw=@=JhC5~kt$L;;05N^Nbjg!m=)Q9HM5~KV{vxkgcOi;z z&ywH!w{4TyaM#7?g4|MXNe;F?+z&Ugp|34`|3qWqvVDC@6JLMR%+Qc2pd6Kq;@Q^s z3xh@AXOFaE%cr_-rFT(LPw(c~4uBY;axcRIPErUe$jcuUH4jO%T7gOwF+9r1QU0x8 z8zHjN)q?EtH|$4+4c`y;fQYoed4Q(rl!EUI$q$;NvLV!qz^#fZbKaY zxptIT^~QOFd(;D#Ojb}ml!`nRrC-0Ia-*Pd>t31R76OGK*Rp3XrC5S%X?^_#GwA~d z0^o_k#K`D8Q{Bp`M84S${pD`RLH>LW@5T%tE5SD;UQEV z)Iv@SlFrVZl7ktgna1XSk?~W8KFs7VX6YDk-lbi!lu<&$a4m;y-)s{q>mPlP51d z#R(+}s&=?QX7j|WC&L=sWC)JKzE3}_RQaE)PX}IvvkxGYsky@mkGEsPtRDBeJ8psq z{YF&Y?MJ%AO^JQBO9bQ2BVPU&^H_n+^PW4Wk!>B{qCv_jhY9O+-)V$JwPnONsOw&g z8PghimqKTgG{D$pUi$4@|KQ-avQm|_D_@$cQzkd45-pxOv>T%mc$eZyCC&8b`aVLO zn2b8_A_%wp_R$s<7HT4DE-R68%l;>?tE$(ox4f&X%RW9g%&t>x-Wie(NlSe0@pv)E z!1?c;p9^!s%zmjFbeR@-Cj{Krbx-z@P3yLL^!TxvoKwS3l`d(KMt@Yk`w69G-^du^ zyo2_t9s?0~cWtwct<3>Kr}~Nl@<5}6kJ8Od_~{7Q)6g7&q$~!*lCa|TKZC7hc<$xQ ztA5nSHc#xza_yHT1{w8ydyypt8*m`IYs*E=P2V2FedKslxXAAFxe`RDcst&M^M+XSYiKDB40V zc$kNT96X{Con|$8DWPVV`VgVC^y}*To8OSy`9N&#E;x07jX0Bjf57Mhiwy2XmBGat zR~+*PzLQ5+g^M^1fIj26yX@VD(M0j@SB1->&!ed3FDYFxeA1i4YH8jToAO~yX++od zU{ia(efIc$r)=A-?4k))P5Y4?)(^QSPP%X1y8A)Zi$UMnngI8IuK)A2cBP;GwzYLC zeWBb3YnL>en%SX>@+JWYNNPTHGYFg>DtYBpRIGaI)-6ZJS5*4_PpA)bh9i3R^K=kf zM%T542{YmIt-fvoBKH=5s`j$EBxWIqtL^ymWGuK${FdD+@EIb$QgJCi^=MAqfcyV76FLeq%A3*=F=2j?Nu9be`w4sCs=qJ+!bG%sOfsGlw3oEM!^?M)G?S?kv`R0l1Q)l?}<1)}>3!1={VTAFQEp zxRGnQEMS?nFkUY~x(@;Cu8Fw_podLko1^RG1ud6t57oWXj*D^hNwNe1MPQI5=zk8B z4*321w^sK2balFy{IgfQo>UAw1Zv4hNvQ}t7QLYs8QI16FC^6H5QlUd8%CkvTx_ha zPZ)*L+l`-xIaUrofB)PEw7UicgKu=#mX|oml$e8LgzQFHJU%#%jTLw?F%~*6{=851 z+R68L+wqL|S;jrZ4;Om|7o54yo;|{UgMg0#=x4Xm-7U>YIt6B}mMBLnLkUH(71V5} z#VF_moF$98DjF*4hbT0zAY%MoibV!5HV}lEE>7L-H~m<_#@AI~RHA>*fo#4e5oMuoE7H27vvc|B^|EJfJtdL@h^1k+5 zE7;CBVkB_s>5-UxRe9E+=d}FA00t39wz1SR7t5DYB=_{0RZo6IRM=?KMGu6lJDQ>e z#!OmlsqcVl0gk0Gz6mIhbSl5)C04|{t%G%%o|P3YYV*c4qfmu4VtTGMXpBwF*INKl z689?(5I_#tO9%2T&+Nj6LC?-fx*^&ldyaESl1}k(`4364xB|DU|GWbq0T7E`k)uTp zy9j0rC2Mw?J+5nDqgMp6&2S%{d<_m(9n|c6;;w-zkiSP^}RE-YHm-qiV`Jw6*%C8pNCF|-m8ygt#xUOy| zm-TUjOS3|~m1?4OyrS6JY)wQ5oO9T;`}2U`(C}cAD|vY`fN(~1Z=kc@o}>OjLD~9c zPadpOidiq#zI*pB23A@C=sVkNFbDTc{Z$v`Rt&n`tJvRJRtbq|Ud;)LJt(~Zwiya- zd2yN1W}rIlTKemxvbHwERS!@W#pXBo#c00|UhQlA4yj38+?)B~W~Yzt_mk`(n4|38 zfKP>Xk(&EVxVt;sg$oyM4Gdt6scuGon78_7a8SJ>Hl=!Vj*UnY|6vU z9VX^>-!uN=wQGO!gcHaO8gmtU5N&MPkuj&!E!S=Od6CT8VIV)-EKAh7V#Cf}%}rHP ztD`EEUwtX(mT}y^7h$hn)r5)F%2~))qT8Z4a{e;uRL6!IZTCWl)zFX$n8E;PD(uSM zAOPfaBG%iwCzY}bM$-j8tDbHG&8b%tK=~thF+0Eg)B)1s=hjwcQPJ*C-8W#7p43sW zuwJOn5o|x&lnC54DJ*rCVo&kXfEF|Jpod5BF3Ll<#3Em^Yuv3X#Gf65EGk8TTe zICDeYJYJQFCedD2? zYZuWr_~%dN(CIU~c0EQ^F#5f6Zf^BdZHL)Ee!0Fu1%XY(7%cPljQAU09$}G&3)$Di zl?TxBIoE>qg5z{C{ee!^+E4<0kJE$*LYnDaSEp9@qnoDeHq9mx|*bHRFn_P?kD zV*?t2nvZuEUG*Bg1yf$T=2mKRRu=nj6gZ|fx{K`TkFl7RO-523IWj4H>J1hg5E?0K zjoONhkN0nZgS8etMk(a>0T}4DkSegn&`iQD5nl?7W%klL7~Vn)q?Xn~Q0RniOVD)e%`hW2b-LWCJ&;7!M-w_s4dYh zyv@KWm}DB11b!aiNig8XDTR6_9r|=SOYGg|-)VqXb`<$ySL(0ur|Ly<8%1i_@?#JQ zc>J(&!3XR-c{aDwdfvyN;wV|om{|3+fx{4T1!`(IFk+h-tY)j*UI9!$8Ih)l&9S?C z*KzfaU%EFas`BCC;YdGj#%)#8O^JOS>&nq2#99GXS8Jl3yBHpx!E;N?FI1o zQ@nhAOVEKhO%&zcD_?-#?76phBDSCrHI&Jp6eB+Xh`at#98aAahpx(eiQ9xOuAJMN zZBLoc;R6TuhwFrg@mj@j21Sb64uALiQX#tU*Ds=1%|M3(76l*ONxUU_U`kqE zE^w7&!*xo(f9oEfLoS1`m9DNocS>;J^ODU{qTN`&ZRkb;iN2wQp^+tS#$4&5Ng zaV4&eORf)Ys;YmohF5_yZ zA6Z-3Fosqg@>R7ojRQxHP|cqI4jDyd@-xr)GKeV$tHXjVszNi3;y0|+8531{it-Dv z9eR@E)aZ?ps!?m^6nirG=B3RN=uJFyt>Ituh%0_%OCe-q+vulS8TG+3P$`Odty>O1BKt6$~A9%SDM z)^K)SMa{`?(bfq%47eb;clmjFMfaxkLGhoOn%Y4l6B!D>(l~~PyB5YeO2AyI_!{yj zBtmR-QtWp0?ajF6&i665YpXB0IO#gvx`k5@rdhdGPAfxaln4jsoRB6W2AUs|j4`=? zX(P2A#%$-D2C5WA5iwRPYJqA*)r`U8vZA8Uy~&@*i6Ac`>B5$kwZ9+7;#zPtkDCU>H(uc=OD2m2GJ-ModH`Ow`x=3P;U6$JTAzF8R`&yU|;UZ45CD zvTa9>9V@gLd5KNbU<5frg$CvO(Yij55In5~Ac5$$YFjx#=v16n!xh!b(=TfUpAHvc z%D(5cSY>CvgV|8S1i7FJ*rHxHzI;;*|ABP|mMwu4r9X~=Y%{gPcYFML+*Yb98j|!j z)^RxFMew>EYCcePlybbQC)-F7GYWJbOyUGlX~z90PoBi@LOWt>*4n?}&GwShZE^A! zE>AZ$^Zu%^s;5t{CMa6WYNZw5xh$HZ8{6;VZ4Gh5+SFtEC&rTknMN*abNtxuhCB0o zsGud`#r8gDd0$fVW+y|GWw*D2~G-V28-Wr@y&R%AXM(PNB zji-Yu!OP(o?h&ha3Qns+6d!Vt`>S8^Mu}Q1fA%CtVG2a$^B2R|OTLN3be31VWgEIX zM%Gr3_q%?YOhF~^GHTMKtKAkcd>gX?ikM2LnUn1$YkS|VIQRMhv7SI;5VS`tGh4QW z@maKFnPBFwso9PdfzKB*vvUFF4M}dabkr`(RYSzp10G9mrYh zQR)FI%6MCm6CQ}>uCA52krI3*hH0l;uZws4AUONU^L&?)7KD?|lw4#|vXs{DG#kl( zWc{h7B^8#z2o^qZg5bjTkF0DZhKM3QjxD+N6P-wUk$4PehvTygdKm_HT%QxS@6)x; z-|WT7WyzVPj6_6=yu2n4b7mFV?^BvbRqc519>#7oG)K!yCB?{GmG2rcAR+6}%a==q zw&(a!d6qRdH+((;5}2^|SI16wJL*9vf+gdA@7UOYXV2z*4s%9{Iwh5Ms=oZnp+l*2bh=m6G_*R- ztK9K&SuYeP_jn7n)vJgU3(x@MPC2bDXWLb>=|I$v&?r`q7oLw3yIHigwK0A~3k}P2 zQNZsP9v1(|y9qg4hX+;jF*>&PHo#{do}T@FJs4LBo>u{L=+Y$v93%ic^z~^DtAC$+ zyd@=BCC}f*@G;&B*YSi-pt4EpxCktHPF~uBLoHH8uOvS#%-dU9?yj7reI^+L<9=yg zDXEU#)cyehU%nVFMKJ~jsIaD}Ro8$0DtL~8LGIMm;wR6ZJ{2}~C>8N#lMLJ&O%-xq zMXtA3-)GE2g3X~8@PMYqi`^{DTwDzhj_3$~laZH~m3K*)y-do0xzqOaCQc=lCo>`p z{BWp0MIKQ8`L5PZ_x(&5X>E)Q5%azGgg$wtrX1QA$C%>$Qd(NRTEJ!&=Wgfq$6Fni zrptuZzde8I<@MC7PE91fomS61CMG6t&X<%Df80ji-??)q&$Ali0FJ>JIvJXXRa-TG zqgw+;IRS`o3oid`$i;r_3I`=QIYr~DcmSwL+RbF*Q*aghzphd&8X@=NZUS$;e}BuJ zI}T&|(EoFq}-?xRd`N8{L z|JR9%=f8B$;_xT>pC9|*zaUF;wl6tZRgG z-A1(Bp*KPGSQK{}Dm1n*!-WB_zJSuQqMTGSl5W)E4&Q1bfWK=V<7VQW8#x^S?$MjF zb6a3i+1RUbK}MzmoO-x?5MSSEWq-uSooRkN+4&J$*V`SNA^o{(W@7c@8szjeIj%r^~Y-JQ%9?Z_yYbQ3y$jO^!`bnN#h^gJ}ug84Y zQTeZ9U;l1oUOeltx8&4Wc43G-e{-NJe2f2ecA;p4${cOg?qqe<6iwUF4|m4ebJ$An zL-@WjJJeBNABE2AT5gSRWrcX6(x3la4n;>;RMau`Yud>RhyB6k>1kkWJPYP3{BGE_ z9peCPYG%*3XPdPyP90F;j@taHaHm5?PCwnz{Ys9iDQXs=WWc5x{xDSqMh(evK#g^o ziYp4jitm3i0!oIK-pJ^1it4|qI)Mb-R_j5;2{oHO$DK$zWcaAm^|JU-LsE7t>M9@| z-HXO@cdPo@f$u|=eG?V|0r(+R;^N)fbKDJ7U>l)fd&gRyT3t^{& z(-vlExgBRwD(^lw0AgY>LRBCf2|aprcnqLmOO*zQ%}xnV{(e4pWiQ;W!?<1fml^#z zzdf6onyb#~)P`f8$DQA3Ti`*xTjT>FW^paI2W=RJn+e^iR@dJHD1&&O;JfGVH4VH3 zpX^qcCN~iD^xVMg#9gmyi3C1y=ksDXc^x%W$+?*Q)6>(ZbzeiV2l4fYN7D>wBI5$2s7g*k@vAK`1h`}KKdyscJ6u`Nu$t06I!Erb$pf7nP zPD;jYW3Khn!(Gi=8`n>6#jp9dw9oOEfk1EpTmdV{4X_rbi4c*txSE8o$nuwTFg=C2Qid1hA`aRZ2xB z1iN0bKegrNeeU1BWq*aJo7+ZYkz?ZcKRcD$5maM4A1IcO0(TC?4mk zAL&VlFpC8m)?Hw~Kqs|RNfVpd!f01V>5ps8gh!j7jYSOWZ@%0BDBs?(@vg3_rqPrL z7}JDD(fN}EUc+EF< zmWn+l;QFXi&u7D7O12m7~30= z#FNhaJ*@hvh(T5!6&t+){V{t;@-O~-MXYe+@%irwwPb9bhJo+{#(#?!!$OPry(%bQ zzLzlR@9Wd9tG;60uxxi4K9-X86=V{8uowLDMWX0pD1&?`*U)mdnWium@mEL$VGpQW z{`V{$4x>7#36{oV3OX75lj3c$Wd|PRa^d*PaV~q$AaOo%^H%~Xu;VBb7nRoGhjMaq zF!{*lI*4QRO4hy4FX&Hw{Ti;a`GXaE{>$;l7)Ei4eG?N=78}C^S!wC1g@sn)VT%vg zOD5rpk%YDK=C@$sMl46XzuX}{^FMX=JqLuAY^N`5JRDWUHw}$TIq=Bbv^jO`*Dt@6 zbG*D`IQ9kp{aBD>vZNSfyq|M*%}>Pz4>Z;kyJ7s}{f$8moeW+O+vOt!m;URk=a<3k zn0Wb+FLS%BLKRDD_*up5AJds(C3L~p+WNZ z{rCO$Zu&_{&dkrN>12T$Kr}?T@>KhuzpJ~Qb(=Vu6l@pqVu=btwp|hxxnh5*vWj?O zWBN_05?eEHy==7};nB4uCs7h6W-sB@e+b8PJb_a<=z#2%Eliy~pjNdFMkN>Xa&b-1 zkEg>C!JfVi`4C2Fx|$BmTa-?LTa$JzyB&{T5iY7lMWA$RnogrCE;(KYiBU>2p1Su~ znfsMh@W^Fx(U7EIgfR~FEc~fd*dOk6x$~zk2AfOa@9$h1KTvnsgjE`w>vtwzMc?1z zxTAv8%F62B>yvkpczuR20w@6{BR`h{!9~cqn=j93td5_oG`Img#5zYyLxWSR_~|UE zJ3>r|pF%wEbNsnL8Q2_R?5BB@m5Hegk_tA7Ei5O9b_zK)2KH7H96I?2>wg^^rQ@^c zR>`$2IzdA(ZW7~K?C1YV=HKh6j_as=dcredn)C0%GI!q|cze34%64QGBEmP_=le$z zed$GZ?z! z0+088IVZR1CLMxEfOljSNhOCNs!oX|N?tWHzg9G`YOUbbG3}QgthvZLNG9%GwzT<1 z(VhBaLP*%c!S_1k&yl&8yQx{<=?o%P+$H5{4~jHivzC52Ux=SqM|6}%6RX=!z!m|GZW)jQ#L(9r7I>3qn{Vb>|D4eZqxW%V*)8|CFns!?7MiQ*-{k zD4pgHK-qSvA^yaM^xrpk_kRN4ZKY+*pamIu?$+D)fJ-~zoTc0^(^XVd;N-+s;u5qd zLmI=}4C;~7$af-$CSs=6*LZpC(0{%y$L6;U0;g8$`H^D#iAaExg-)8+G_PILEaVlD zQB+)kONf;3QTe}1kA#HS{mUd{ypJtv+b)Vi2#>V*MJgVm`T;OqE4F41f{N9%*ndCd zv^&$Nl4(<#y4!G*)stT=7hOn6+Nn7Lku1DQ0H;(NW(L?crbk88s@=SK<*x z4>1?osPPR4M-7}61)Odf#O)GswVu=biGmTnRluPuYZr-DqfT?kHvj=?vkx&_+C`#7 zHDRq*_jjxF|9c+2;3v8-xB0z%37u9y?2E{ONqOsBEC3J}c+OviRbE=!VVQ@EgCmt{ zr0ai)Q^{aS`VL9$yaMoHM$VO@A2FJ~ue zua=c16Ehx?9iR0KHh=m_Xe9bd>wcU#{{FAOY`qr08^MSKAEOV|A;YijAz^G zYs4vse50Mp8ASZpA(D!UqzuggEF~7L#cR-M zqa*d8LP-u%hT_SSu*vj{H)QwKgq8&7fp%fv3dSMqx>+m&0vf^b+gP~3(}0Cnoh|j| zzZIy4nrHfmiVq&_q&)TkzQ1#SL1Rwc^J3P0Uho2jW)NKfl=af_ z$~x5l*;VC;pBOCVU3-tkK`R^JNyaeTYV}^fjP=0Hn>wvK#4FK)a62#FW+(;GjQJ@& z{SpsXZX_;|kiEHHNw*^Duc5Xq^@;8>btd=y0zG2-Gc)6=!VRCA&E6YT7Oc2`%?EUd#+6u4OGcXbkR3B-1*`hZ53<>HD z{AbVda}&#|Cn`YZOXg?;^_Uq?&5m^N3!FZkTjM&?nr+%u;oPYM*y}GB0CO{oj(Ir3 zold3M5_n#H+ctk)rckYrG~Mi$Z}z=wP7Ag=FayU+5VofoXBZg`O1*xy(b!M4Rc_@K zKYHNc?1$TFBez3GM?<->V#EBWHAhspuv~l~K{%ywti-We6Js3S?KeX0%Go8$eEw?@)CYSf4VwSr1I<6Q+#|m-;=f}3BshLZZO#!Ef%O) z2E=v*2n_-|3?GN)<=xCS%@bLM4IG$wz3+C3r~6g*Veia&J<+Rh6XfD2#>Cy@L8uSWtAQBy0BR)Ax0CxuS=~ z6X#pj8ia*~FZmul86*=B;P33>^5fr3kH~#E?<*cqiY{KSxA&+h(F$M@RkdV&wpk^b~V)ZlmfXtu$Rry8U{m z&S++xWn_#ypS)GcTux4&X@B_&y|WT%2q%OKsZM?3cdFkzsuGmO4%~1inVXHUl!M}U2f{pbLqcnVj^&3wG@IM!CcGX zm3X+TIIoOlnLdABcI}k={v>astA7h}k|yGZgQH-?ITy`{d|R85N!)1&w+2kKpOA`dHW%0UjSel8p0i zu0C<(ks5vjfKwAL5Ie$3@~6seV}%~Md%_|j-=5Jz)Vlnoh7M1>)u={w{hg^^CQQKy zUYJ+QdJuP>GOaW2{!C~Nb9?58{sWOxiNNxf#N7_}FqAt1LwBVUetYOeokvZX2q#X_qgP~F!3R-Xr%1W;*y=YZD-5N z!&PBqbn^G={B|W8CT8Z^kaI=A`H*C`Fgbaao8PLpO|nQr29i-R%C+}4M$XQK85bkt zsR%6A8WVfPPaB$>a7yXg9i_uyk;a}l2KApa@8GWU|@hQjpLCc z$wA-f=x@Yrm)MEpx;M!8_UdZ2@{)KO{jCiyM9ux(7+$|cIrb+UF&=hz&hebR_dE8? zjm-j0{6BWb#5W*Dko?_RH~*`gfFANcum3H*h*zTS|FNQzSSiZT!`b(wM69r&r0BCV zIr=1lRP*!m;E32!vkl44_5Rkwp|pVJbq7sMHZ1aXQap&-jx@I{uP57;?&6_!FPf8d!*Mz(M1$UL}Gl$QBj(Ouaoo247hItuDodD8->7%5Pw~4}Jc#KOU zBr2*0CK@(Q`mpHGbjrruBqPn-%1RGv;7g?GhBI$Yq#Y68_f{pnp}5DbcB~$QV61P; zj(m0zkreE}oBtXM&(^rDS9MRg!bU<{JKV7#FH{4^dsowTajEtkGk&XaVIcmH2_YWW z^U))Nip*o9V?9H) zTbCfId-L7-pEBFE7|ti@y(ATF1qg@>JS)?Q0e!i zm4HSlRaA7*=MbA(YQvQ)BzL0$s3OFX?A@c@`EHQPId*QkE}B2Em0} z__Ve{@Ot#DyU|u)^UISgecltdHQ>(>83R|p#?ok7LPBeXYVsTTuy(cg@`{R-d-tx7 zqy=2La%I@1u>BtHbHB5toLrUIVNO2F1}K`Q2A;)+3z3g7(1hP1VE1C)r!x1cRW;ryfV)|XUEN*3BpzUn>cvhs}yzB)TDw%#@lHIcpZ+R zIt7knol7>ud4Y&7Fyl-!r#@9Ickkfrd4!fXD`Uz5#HtK&L>)zmU@GyNIg&EeL<$7> zh1SPNd=qvRKsPX08<7SmWK7UDa=Qr50=wf8Ge3KK8$dBlYEB|!cnxJ91~xF=2pZYq z=*X7>f79c&MYq?T&CTCY5t7n+-ejvsINFYlj>b7Q9Ol#`h7nivS61lNXnpf5H-Nnc zsGvl1(fJqm@Bc!~6pP1s>qRfqn_@lq&Ta`1 z_MyB8dF5|C`r{mf0Y@3nP3xQYFcmj!y92*<2&l zw@NnvW<`E0W!c8){X#Bc`I$Bcy_jWZiWYy63kb)-Y1d4QjB@R&O;sILvSpet`W$Y3 zdqu(}3o3H#yYem<p{uKC zgE=b8tf%|aryFo;K6-R$M^YbbY$73WA$UCmY_<;V3ujkX7c3!vLF|OAk)NE!N(!Y{ zc2iJv%TEQQ`>fFFB#d=SguQwm01hGnM|XYk-znz;Wj+?Xbs32{CO6H9AX(B zJ{J5TgjU}77;i7+bB07~2|%`3u(v>cfYXX<$@`VsG9M5uY7{AooEGlb+KSkX8V7Ue zkk3hw++&7#WH+_BCsoF6jcyUcU%x6k%esrLF}y7*dPwyej99p3ExVTM_gCCPi+CP7 zyqqy1B63ooIHBjZ#Iz9vSXv=`F^K4pDKECZI8pfZ`}gl`!JKJ5AIiUcxjFiS^YEFF zwBZfZ!&lulQba)trU$JXdbm8g*BLJTwY&D<`SdHkf8Tod#fD_Y{&3oOK3$8>&d#k{ zQ^Q4VSvP_PKfy%v`%maa+A?oN2-z#Nu>^RE03~US6u|~yZDT{eXAkL~JxZd)u?Pr= zm*p-irOA-~f-MjJABaGg78R|K9V2+bXF*G-13z)w-u^J5&nO(5oKyA`__WX!hN=40 zW1Q`f?Eq%+Sn1TwrFR17&tGFJp%1*xeXHuS?25g#M50OwVF&H5UAsWJ2N0HetynI* z{l>3%8rd0`1*0eUeM;_HvAKqCqzG{`Wpt&sc*QbiSZol+UqM6l(4MOV(9n05aFPee zM{*frXM$$a$JbXqXJkaylM1dS!yCv?HrE%3$Le7I~PXMJnsp*+r#tkb+}J}|Mbgpujwke z{--Cd9=HlK)a>jGm+E2F;gw!w7mszOOThi&F+KHLf6De8UT%K3Lv!W}md}np!$QVX z%!3MM;Yxb#9L)W(icuofDPMwbeuK?wsz#AaOirw_-*8=etcuqlDH`_7P8bK+H_fTzQsREoW}v2!8^boMY`GemL(*&4r|Lge}~s3 zhWoi+?1nFmvcnMbIfio+k*dk65VyRn><{kFa{E|DK1k#erCAmcn$GGsT?XKasxvO( zuz3UfWFJm=AcBLJhex^k z%3H83u#+_vXlQ69x&iwTVJL;4exE=?L>T;MUDw*1nzAlYP&QwZfpzCtd#<{xMYPpV zwXPJm4aF0mzbu%hzD;bv$Z9X0(E3`d9)=g+SD35iVO@qY?cFk;sOY%#?MYZR1!{2= zUFj0E^`x>A?oHJZ>))uu?dvLX3Z6EDXrI}L87v=MUANi#$4m5*MB*#uaY0zgOxEb+ zcNZ>AeC37_-G0-NR+Hpgfm`(C!zV|FxSMkyU3!$0V+V)cq58~kU@!sGAuy!|kaDz@Bl3RCzT+w7gcUlmFH`{ZMOux~8Q?j$9E31A|oi5jNHLiT`+9mT{c> zO18WH+&Kbi*lz0Gn(p{@TGIM_q}56ZtwDH%D$Hp-sLs{bTb<$J zo6o~+%5yiL>D-4i+8-_#X+Z&89>A=Np_IS_ECAoyxLL%O(5_CuWw3%|41d~aN*47e z7dcCu56wO5!LIrs1=gOY1{`82lQ2r?POy&xi1xAQmb^MQE4`hU-A23Y#jm#Ze4E;~W$S+N z@Soy4G>!J{TS(RH)GW}lFza$MGwW*4Ptjyf-K)NmtXAKiFO{tNXdCt9l`Z=M88Qq{ zIjnz}=OdGl{Kpt=RgH+iLbsK23`117&Fi~P2t7t-Gt@hx_T7c>Qkh5)aq6S)!@H!;W%3VaZB^DWZ1(VU;0hi^>}n_4EvV1_tB#cl1l04(g|L> z1+BzPTi%`a_&)LYFKo9Oybq}c?b)W}4Ep*vBl9a=>=a&7eeUc$Q7eTJfhXcQ+iEpG zdQ2V2CSao-)==E8R0u=u-k)_T4n8lZzs@q25t0$Es^aMuYXg zzt)7GJ6U@*i{=^CXSu0DpLc3WD&-wcvZ{}h{1(Q?y0d3c+2DV9K7Kq0|EABS-nDlV ze}w$-IlOM!^~M6~Wn^vF!u3Y$8Vluy-Q{&(Rc+qiOm+ypJE~Xn{=HIue(~#q{u_X> znqD1a@JI?zvh2$L%`A7<)^=^S@d5^%H51CnnOETbW@?(PnW*AARR(vOgmRmZxWM)k zQMvR31Gf0A+bClq;YtyzAHLX-_ z0VE!E>W$jou{%VNym(2pu?yMYbxoN=oEs~8#@BvuN03JUpj-M4pMQ+A!r*l)gu1Nu z+@V7iqHD{$8P?BF8$9{=r*yz=1#wXzqRc~?4({i8-u#p+wyRw%1W!K(i{M(;CePR$4T<&R1AsUeHqdic- z9o0Ox`!pN3Y+jSX+`27I zbgl(H-0y~!=9I-hf&y!6bTj18>47%4pW+DQEh@}kTN;dley84;=dqiR_9*VfEq&9Z zv#La&iZiw=SC#$anOLs+Up+1 zN;b5d7DT0AA=F|&;m415l~iQ`j@H2QMu*j>Y9}ZdJfJRpxJ&_6AH%1zIi5{;;iK%s z2^q0%o`m{%*~1KyALHE<_A1E86dv7w!sAa@ZrUdaz8t=^l5UOF%zkNx(6BJy<3fC= z1x!X-*lU$|-2H!zIGtlW|3fZjQUB|nc;(Q+5VSEug69$cIleNO*_EuGhE>9!+Zt#1 z=I$I+Q$)Lh5GVfF2ViYwSvDsj=wT-%ma0~alBATBl;lC4+<#6BoaW_~U(J+EFt3ZQ zMc?q=a;;tX@Mp*4i6$llFSh~NzF!qVl>{$hluF@ysM$-st`KRg+?-9h^x8Vwo>cJO z38ofyM4O(tn} zoBx8Mm#3$7cc%lER*F{6&c$74v~p0`J60WWQ0>4ZsS9a_r1iPJzd9&|vEnP+OrYo@;*VB^2^ zOjj%0R36=~Eq%6HqUgq|Pi~KcRB|&o2-EN-Q+7jC7!)GxX96>C)#hZa@|zep=g$>P z6tj7-+`CZNiJ!AxTjnJv@Bf@uoRPW0zXhCWSX`fFD6OFrnqFblY{1inqs&&JMkm5S zWpDGb9*4n*kIDC$pVPa&ag3~JP+qE++J>t((YJDR895UE{`<#9D|~6iFk-qK0V)aR zduhtqGEHl5lhsoX4(OtcBap%uEALxrX&(%%#%GsD2&6vF`X#Gxn};PH@7271Dng#0EXmBcuchK5XC7^#f{g zs@~betEh3|TL#r!?)!VwijITN=?Gr;w~1M{rbalw&X(bI`?b|9h?VEeC;)wBBXlQl zh*XH+cy2_t34H1DIWy!dsiiIDTzI&%VWEO@bc1){)maC46ZQcGbegGN*JIbb+g}m% zGy0#PXYw6677!-~_y-JBMXt%s>@gJ-@PxJ$p2#OecafB_^PDm7^&pdd$!=>lnlqRX zm8P4wpT?0{Dg{Yy=G}#!@$t$L0hw6*XlQg6-UYF#o45CMy}no};^ZpoGH@488DDl% z!1Mm5zP|PKjddHhwYhhORTw>V<uJU1te zum_}hcI%t3Sf70b7}AG1u6;1Be+`5q4_0_fORvJhN?QK#9#&V!x@ahq-Mv&fQ(Ari zQo-@gc-j66)dvqOL&Cy%O?rQg_U^yOTbGg^mSEIayOXkQ{)~+vO1{M@=BWHUUI1RA zHUo0RoBXjQrGv-xnWdt@h_&*&dz>fq>s$4XKJ6(qOrCvsD@LW|t#0*aLTFG>9@^ec zb?g?+F!c`z3R-IZ>^WWX7BgXsbmKVT+33Ttyj~aBioUnkjZRX2PzYJpe*R zrd=@b!fUeOA92=$U<$@7CpMb`E?6FWWkv4Ri}@Ck%9hF#qVfw0WP2Xeme+`42>2*_ zpH5%# z^OHcc&h4sQkTcfpFsPHr&A~Aa5niBrzSAk<-|lqdGo1}V{E6L2w@&fT)CeJv2h3iO zB$}&43Wibk8yG!)^k_ZbD$2KZ%frfbyFYc+Vf;QyzV|_d1M+e~6ls8a$@U^Q>Kokn z4&H8Ani)hg2d-R5Yo~59EMJ?B?%$s=-@ywWB1d1!#^Tz73^kj}V!f2*v#w4WbUHYL z7MGJf;n@P=seRd#Aji4UIk_#$a(AD?tPBIS=X4_eL53eP^wM#6-Ltc^FDR<14FD7X zrL7p!@~kYLhf>5AA{Xm+>sAhnj{Lce^@)u=kKp`VyJ-Ce{v2Rsj~AOsmrKhAbLeIm zv}swDxJ>mDVHPq5SYqwB<|bl7er}wGMn(wMwf;Zsy;WS5Ti-5>x=a)d6a@hh13^Iv z5lK;$kZuqVkQR{cP!W_6gGRbRy4yq=X(Uy;yK7(5wbrwr?_i(pqwn4Gw+?X4xMPfa zjDK9QQE0hD(?u?znEZaMCHcH+q+QNvl(L${t=J@mv=5vEGXG)$!a_HH`~MlypJkt8 zat$4|+NQVDtM~L|1owT;$4j7=rz!=CqJ9kWC{BS^XS2R+I^)0l!*EUQC4vG^qNX5m zEbzR8;=`f7{k~5mGBPuh^*b{M2%D*zgTT(>p(ZY54C;*;DK53SbJwD zfQX-)o9911T@ze8@LrZ7Ss_`+Pc#`e=BYS}-q$2U~5v z$A|ZCI+PtZ+~wgpzX)<~9|*98CVY@kEOA)z===7vHi(t0%p7HyrOn+m7uAY~BYY$h z$^P#2RUOkgbyP%CQ$SPm)7(8;1{M|umdyOoZIZ1IbahqBoF;5;}0JWLvjM?3q8fa8@gs@X27rMmiU^7UN<)O#-vx`w>#qztrL+yz4-S| zM;4TrfrCceW#z~N6X*&@9&Cj&5B^3R@AVJBf=KdrAmEMsH@Yawav%L_+b1Jq=r>yK zJqEE^4lBVAbKvODFD(%tAii|J22%zJ0d?knx<3Q9B}c#t^54K96g{Yvru`CI9nj`f zL@1e-r~ZK!1J7Xk-w3kL)PJxPf4=>l04V%DV%hNf>+G+b4Pr4%;jW@c8Iw8JNTKttg9?xm>!8}0vmt{gzjXN{;C6EtFq{-(j9tuTLQMBAU#l(cdo(#mT@QC#7z^26qxdG*rRE07pBpxy1G&JD}6+%xtb4+?mHKK3N{vzdD zf8`$>Jk->{ZZmzKI97VkA=9Nvq|rLl385+7?mKwjkRn91+gvY*SIbJ&Z35VG4{bB2 zfytDZyuZIm$%Z)A_~e#^)a-Nz--9$38|AN~@6?B{CA)aaS|)U$!Xuy3dF`6497Bqx zCiT4{tBt&y?#Mq!Ner8ZbF3yhg(u#PkE60pNIQwrKl(vm~`YfoI1HMJ32W2 z`(lokmL_yKl3NVWVo}L4zGS&MTekJ}>(>*_tvO?qscHFD?jQ|~zB`$?QF%VxH!HW5 zsu+=(tLtCgVG_I>*~lykc@WUvG^l#Jr8w(z_u<2?9`((DDdL!DjnB6yxUvH})|NI_ zPp#h2sQbJ5Pein5d(0Egw!|j5t0hvAS@fZPz4I?2FgR|y?LTq(egujqT}q|Jj&IK` ziUqTsKokk+eE{F`WM{kyZNS&+ii+j~udpHVICjie$t6|rh{Qtit+hZrbaSH@rXPG| zn+6(YW|`{=-c>q~?2=XqefyS+-|UgatKEhy26ugy?#4l;>36e3Q372Fp2CYs;o}##Jdb+ z`=G43{&}Xa9I+y;YqF=O0~en<-&3MWG_@Ar!4Od1te&}SJ?-+gM&xA7JKdeb`NFyQ zDL9-QI70W=+|`f|BubQ`<4A0N|GuUdtr4BtQDlPEKJw=8n$}(K6z@vd29kQ79%f7OU#EbShE@k1lj_5J^|#c5QbYl&coLfC$?qrU3Yf(uyTq#$By*O?00PXjaUYj zxfg6~Z7(Th%5w0CfGh}GThdPWT}+e|IM}WY6^OpDTPj(yXo?mX?N~U#$>Z_jTfIY5r!OEb}0vX(i(*nbDf(wncI{SmRIedUEd$0D4!^7`lLPye1AmZF>D%in6w z0!KIAdFGk1-Mp+APsj-M)fqkMW%GX*!L!~cgjSG&iJ@y9yNGB7QVfHMTd(t&Agymp zn~%brNvRT{hC)ZzR8^G(CL$ztGSemZLG$dmEyyYf6%{BBGNrsaXKL~29$dYo?YB17 zNmrLENGlCJTfh%m9a0yf^|&3qqF*0|q5k>};`p$bLxOWlUoaEvH30|6qHQ))a`-Eu z1Ohu}-Z7;#>q&0&#fKv=?g$EcQ*xcVe!cMW`O+CT0xT}9plZ94GDEz0_~JWqslcF? zWOcqv?3UfDmfv1dJFYKhe5wJ}lLRhf@1c@+@KZ~R9jA6)G+ZG686g`kdrk4Ka}y`JAmh0f{757FNDhJ(q(~FWkR1 z#xllV~|C50o*})Tr3a zY#=w-GK58^J4RUPUHuiyRW?S^YTfIxGT+3_2kYJrK1Ti3hk`Te)yQk?jx$Hf$z!Xw zA2`8s*Sfplbdw$%COl8Nb6NKAyX)tN0FXfo{Efmx`>fs&Bx|oaP(p#&t)E%w&xnW& zt#Y-ZWAwG|o*o{-oLc2DWD0-RQdag>=2AChih7u-(%QQe%_ z6hmkod!67Zd^IBFmm~-MNvVqSupc_d4y~djg{>vO`DNW*ZziwX6LxaKON*AjN@a^< ztu0AT#Q=IGbXU*ix_qRj7DL$}c5#xYD0=eFiT%rc6^CqlLvJ6TJQ_)j3K$kop^1nH z%C*H!&C93g=*%I#(4-g4O5u$Jzu=_)oK zVv_D`$_hG3oT8L)HW{%<$@%e?rk|OexyDL)Rw>QKt?yT&zIw*4 zJSs#FnA2!=NZQU~Lis1eu;#j4FG$G5i=&_QuGwj{+6*;K+kuj}urTRp&95S}M~clx zq-m%AMNQIk{v~9ao|CijaQc2C73#r;Lq0owOd7wa8dsa&ut5G@Hgmh}D#Tj#yA5Dj zC`g}(z^#!2$lA|kRCVSYaq!(mcQ|q4*USUQ^m#7}TmFSnc8^D6ni?i1e8%fVNtd>;{wA z9O#Exm$b6Yj(fUgQAqzBuV}d?CMF&{ec^&Bs#j(`E3&GERz}^0-p#zulWB89b>!S? z$qmbEE22jAaT43l*zSng-9S1ic>9>cPEp2WyH%9Ij_TN-|9d_W@&C%$Eltf!$=%-C zDsN!Yp01|sl}eNY`v{5?CxWb}+yZV1vxmOxw^CHpbNURT3jjdR4uW-tim14#s3^$6 zqM}*3xyJ--t{RP^tb|g@ZU%PtN#XrTo7tRTQIHnvy{F1dp+kT#R3x19i0II6gdW*AZk>p=nA8-@;y=J z&PqBYF$;I_ZfUx$OLzY8n*uBmpiAPpiw}*AzWIco%4uqB^k-7JzMMrX!BgF~qzOu` z>p^O<5b)FWa+Gbq3YK}6+PXy-8nmUBKy%@#xTUx_YVox_Ay1zelf{|+dqY3&d9@#s z`$bzJ8?lSvD88h!U+q82Ng*sO%oLdf!|wqr$QL<%j?&ufrm1KxhiQdaiabc|>S}6g z0(-y^@TR=FX|?o&fh2ARJoKl2^P6rY$%Bew2F`ho_8GVAS`3?CosZ>t?v$?IciXlhH%ho} zE4(WD&WyCn1Ff|Ol{dJG&i{Ia0f^VldXn}~Bhptss)=2{ifrZd;qHL8pRoY%bv^SW z$NUVNJ?VO!%lKWfRMV>E*gkWQgP+>!6%0^7X*0DVDKWo8@``Cy&BEO9UZCf3$-p3X zlb)!=J54}+hVxn`?NRvWMiC94=4WBE8duc+!ImOlWY;nZoXJ5%{|1Q~+WK+=a@sLl zMTbL?m_*G{$7RZI*o)}6HMbYqn!}kPX8nV5tld(#wP->GH?T0Ed@l$Kp9m5?#>`M7 z%CLf%a${rTocOylu4tImEt{1myrvsa;F4GvZF3$9KW~E-nTm^;T|e-(qk;EvgOf7|j`P zn@J83cm6KXheh13&Qlvs%a0z&Hh+)2`RrgTL(BY#`rRPz#GjP5c2~!GO5B@~GtENb zk(ip<)B6SF+F?eWdoU^}URPQ(Dtp@-<&;vggVW7K7p`3SRWrgm8;Q^wzV-+iT@UVK z%{rl8Gd;IZJC*Yhcl9B% z0+1+Xg=wX-vTpKwq+=K<)|nKwjn$nBybfRX0REC#VmlXyukG{+2<0}_gqt=+PT|~` zYD^U+yWK?hQcq`zp@LIaQloqdp)(xB&mN$K!$8_SMn zeH4)WmJZBvKDv($?Oa?OawmU({)c$_(5H1?o5)*dO3s!Q58+h}9`y|hDp*!ByFu$3 z9-c;airr{*$bX!FKk6$;-7yy94i`d+~Oq#&uX;KF7)=~l61mq#ltyOmo@*L zvIRlBjupKefKU_)W5=>4vIXHC>5-1!Rb)vS@Xf@I<6 zgSec=1G`eyqSICW6NAs*bcwmsv!Bq}DF1rY;3hfxNoC9xP0T%8Kc9ASeJ}1Q$SNp! z*1R~ka7h4UkVq*hiNQ&rrg-W(Z=$K_JLC&p`>RVX>FJllckI53@~6hes*y_GNj|HK zyqg+_JT4TUqo$S^+@Y6iitDGFyDmMU$c(at|;p3dI@ww2sz9E!(zFyRELOG(Cu%59StlTnI_^Z`sNY9+yHZq4x~y^m>} zFM?V9){*2S{U=qCI#NCd8VU;K{-(0E$u;{!hon1eQ)ak!8u!IC=pAEL!&9Tw-#IV> zMq0c?C_`%Uj~{;OxeiKSJ&q1ggZ~czB$_i)*S)-7l-T?-Nrb3k3egr(;zrLJjRl$@ zOVY@u=LRn!T_nTOK8gjUD({tbH~>J(ISlM)7ZRTtwWr^Bc@)c0Q^_5l?YolA&5rSC zG0~&!U1l{=8FO9VJP}Ib>P1c)N@;W%*|H=jFH7=X{B-#BzxQRw_+wx91sVblpEX*EpUC|EgI8-gdJ$;(SzL4K`ioD!*PV1OEHM`(4k*C# zb+T@`hliUSAthazM%nCHS9((1+on-=!~UDk5~E(4Q`rWUB7qeR*zO_!Z?TmBw#x(h z%hRJTbi>b(!J`y`rgn9JFwFz5qWo*%HhTg1GS#E*biqsm?a09Z^*Z(RbkG_F_K1pV z=NWe&DDQuu%dC`nrhZ|}OE5*Ad3BW0_DJ;UB5ZAIQ|_P|Um(PNb%8SjfFkrCuzvtZ z5GqE_b@l_f@LKz=I%zWCG0^u-B3(YwZfP=ftzoLH)A(}dh1s5xM45BU%GtM+CF*O@ zzEshAnuQ_kFVTP7j4kRWN-wcicDKt}W7P>3UWkZW2|lL}9~yxl!E4mf-1T{~=Kxrg z_P>}7e@3NErT?O{ASJeqLL&^34>t_~C5{WC|Kvsg&-`-P=AYga-JsX{Ug^?Q>D*m3 zQ60D+{lwhy+W+~7C|XLOIc90D%tomyEiTXW>C41BzG|>DD55 z9=%oB`jj&&J{|+ohHVZZVAAD)m9oCrX*<3v`{9p9&2UGM`L{YvzOEXJDiVo$`^1iO@A);N+awD_we_2vWtezWbQnP+d)sdR21ej~^XktxCnl)jCr! z9@S+qS@9TvM3Hn6I^hM;BHp*NY#M%#k4H^iopIZ|u;M#~t2m zaHr`iv`nsO`?ok!ao3=zmBZ=)Go`5LfMFUtfC-sclVElPCL&Zu!&$FarJ$r$$5eN8 zoDu3oe0KBnmoKN^y`;=TeODzyG<5Ao}soD*~cb|Nc#6_up@P`@7jlw0=I} zp{&(aD`~ECOz8i1=KtqMU(v8?krS;e#KgtK#l=wk?|OXL%d_ME`O*LL5&n;d{(o-} z?%w}rH2&W$`M-TjYP?kOld)ea6XmCPOP(Fv?MQO_Ru{V!C}k0WP(9;V&{IxxD%rPq zw5GOJbeIWPOP|Bk&;D}%>)t-p+?gVa2xoL#7hYAR8HV`M7fvoNdy^hbczF?|ySE;G zKg9xOq8bGQWy^=hG-WF~&W46#(nb1^Ztf{58*k5`yTqQ;Y)oil`BDh3?DPB6wmVz> zNnoXxBNTNNWIR?|{>1`>=;~^(tgcezF+i2-BESs@6cVv5;}vVG4%5YQ?{07^ zEc;fy!AWi`X2&l}?jt<<)3cOUG+nbiJ&k=-ZMn3L?uf{z_p3rg%%Ru*y)Ku{DeB1E zH&33VuC1&Bq3Zu>f{08SNI!`DGn&syd%v_GP<`WJVULf3x zRl@qloRugOCuf;pKseucoG&FK&l|_}ne)Fie%*PwuF=KfvXy`Al5$~D(byuEHYTOQ z<>pHC$#QR*7-?$GVsmMV7t51R?5{hA){bFoSG|weG2D;oH$N$V;C}cA1SnwB^;X^K z@;gSB;f^=M5%p;rcDw9n&l=n1h_>`q7q*zgLqpj$elJ6)+SdZwq~8s4fKv;Fipg#zMckwgz_{zhOsM_Hl=>Cu1Ax zl0k0}IMYx-tPYnjyKHAOX%JYN{;;{@M|L2JI2F+YaBq2s9#aJj07nTq>NezGgY< zYwRNX=LnwT<8QpPao1cLZ@9R!#6X0S&dn!br2oOVzn`9$|EwX z+Fx$n8KXwMs$GGehVqEYsvqH+zrN&oC3%j%rY252WV1y*-X;QC1DM=Ex7dafL|a?WZr(wFS3R zE^M%v^|D!O;O9ROd+^ywox2;%1{o};^3V3{-JQbx!qG)&hTGbku*mZe zE(J&Pe9rUg{)4!00UN#QpD+xP_C*1O@l_xPAYay(z?@VsmM&w#i;ig3>!O zNr6dIvn07R(AXkQ(aG;T#fJqB*`k=(!nrnM6fuG2E@${Bs<63n=+wswpq?#AWn`qQ zg)rBJ#DqalY3)&8R7&0qb? z4SQ43&9WT5mi%5$;CXX4ybQm8`0yc1w{F+&-TG`4S^ za5Q0I@xA#LiJ$|TNg$l^QY3X*M{mw@q(d(6JlaE>#RUdA9g1hS5xHcR1L@?=QS7## za&-8o-t;RG?Y_a*b|imb>{{NkX#PZP=NNw4SmDyvVo`HC^6rUD+@Gy%jn zF?o%IxH!}Dmo|zL&;;k>)xy=GP+2^TtE&w!`*1h%@-RMtSE^LBTi1~jC-e;ouVk*8 zyODu>&ICl^q~I;z+XaM^4#MM~X5)np z8XHG;uFOgBt*ou_Ep(wf_^hkN<8 z!5~b)PtDC173q;^mHbdb0hasnbdrVM^ddj+{$h&duS4NO4|KeyFwJDE|Bh$Y{le(lvVZ5oA1zZ>@INRDwA<=aF|_>nvsED z81;3F^gZXX==2$UkBE$Z8f{z;tOtGk9f7Th#~;IYpkKHF6+4Ui6txtB#gAyF8ZIK@ zp$6$0UrS_L#QO@R(wug@6&Tl1H^cORah*iUy;u+9da$*eIEtL2f9L`G9cr{REMdc===~T>*^}S-Sb>&{Sv_{5_~_S@_(?;mL#Ec< z9XTsJNs{!fsVchPSC&@h(CCxyht{aeA$H>~#U;S~Ovl?z1-3f13VNxpakjiEGkp^n zm_T`|fWugt!jgcW0;?4Jub}il`>zF)dMP)^6`W}}{y`3o5}%;ozkeUQs2I^=5I$Fh z;h-OdYrFk0c$NMAXLA0X%W985R3^6OPIRWce?MCqVIIo8M%ecP4%-u^#BnU#S-Q0i z8>iC`{%#(T0ao9(joDC+IE;~Vs(o1|rviqF%=#>cNMFZWL_&CHA}4Th|U35W=b*^Y*J;-^8^K$bbJ z3CeB&5b}q_vokYC!H)y?an>PwOT`2}X7YLG(dzDbhvm4CUT!;)3k%)Fi{sGe?*IJ! z`Sa=krWf1K)8Dz(wE=QPkE5MRKo zK;u}!_UYf5nKf(nU%)`sD)+iNe6RRH!_(p2XVnSXwMv-iEeBpz1u$<-$99mj-yxy2lfptOsEVoEDdi) zzFw<;jN)8-`)G>G(ondrXsH2?6Y>5O|0m)IiE!Stp%8KgPkwcNB+F_d@2n#ok)T$3 z%-xTx^Am=enx|<7IivMHxe7xyy>$XrboCsA0doZ;7FDk3aRX?ahQ8P2%5t9s@Tt)H zWuO|}jMSJOa=|<^UOwac+{0rZ0JVOf2osa#F=4Piy$bNX5Li;;h@QBGeU$l5Az-*i zyW@TSUb{H6SXo%Y%fzv?9n)hAzSPr`HB{qg4|xajOKR&_t3*${L8j3?GaCsYew!yb zW6k`gTF>}IN{fMLu^!>-YA&-|ZTrv!r{Lr7Wz`Pj?mId-h^#UZi9CK99etzz=~_df zyIhid5Okz=X_anRO~AoMB$tJ#UM!_`n3{piqp`T?WYyB$!;8dTv@DS3F|%(Z1mi~hSNU*55o*+o}5FG;VFI=-@KaJx+d z=jd)B$Sb{gv3E97ATp4{q!d}iWMEl+cyHcPfOHb+2Xi4In;84yhA*GXThE>4j3qOM zP;6&*V!UyE^zyQFKC{bEWP={GM@xR#drlhP1}rh0WEE!JJ;LI`tyEq48EXJA9$19< z$r)%sg|UW=+`;WwPNU`j+f2IX8$!0z9|IUnr#>v_ z;n#hv8^W##&vz+Fp^;%89u_TMAI8oIWc7n&0?N3G`cLvz{;}c4(&g2Ujs+8wlf3sM zdfeJk&iwUc1<<2d*^@3qeM4j9G+WT+bAI{`a4JhQ@a7q9m!~7k!qrE5;d`*Ws`idW zzwyaVV)J??21OCGs`pB)fPRT4Tqcb9MJ-Z7l6S7`gb>aK>_hhUPyOF$N|%W zafbuKzA)B`T!+?GvCP;=UcOS?e!HaC`nrQV2_+EThT=^5pZ`Rw}hmCw^uT7Xb(QWfRM6zmsN|5jQF#$Z54l4uilSt$&Y4(xq>nJo* zNj$duX92dksT>0c;q^&)DSlq+b$0HrI7D}hC}Iynl>JmJ`PjnIv`SIC!AOzh|bk(SC5UQclmq_?ck?d&MC@v>7M5CL+u#=RA_gt`m}oJxB$%ZQEAp zj+h*SfD)nKrKm%cCM&b8(5rHHbahGr> zcJAJdUJ;VGGfQkJg!J~P?_g3Dv6-)U{!A`Gu_0Rc$WsCi%~)uf^awIynl%}!pppw^c6?}1cEBmBP_Y-rn*(KbSxA7|LG1FOWyTXB|0S@ z$_taNH80h#O{m%~p_M~O&1A00T7KtYEHRe;>!OqY?q|@pRY%qS+9jDM;iY1bEMIL$un) zu5;z7F|V=(T>sil#p|G$B2S4llkf@y*s$ua9OaUSBhtWBe7^JYky(=VxY_)zTV37x z8avE=T*#kAKmA25RJh6O?1URDl5(7=UhD6$nceDWJrn_uCNU{xwzpdnG4tiLUQT3} zJFfBAyNjb%l_1|a{p2*170qA}#;RN2oUERf=&p+;vbMI?Tk)=yl@&}v0Nr@?^Zp{w zcC}L^FIRR6!G{SB1wYSI*wBJwzBJxa-7ZHaSg%$BSQ#K1wHO!X0@ph)lv7&2^!IXl zV6FD{@L(8VIeBuSwXVe=XRps;(E>tZ6X6Q=(}xWPIUjF)#DC>Xe|_*|C?gX7C%OUK z*M+>Cm}0RsLVE`@5Wnv+>E+%lN==Rc5{8gcq`*r&RIQE2%g3j_u8v`V;I!m&Skskr z6T9(2u>OE!KR8!=Xp3?f^+wv+3Fs}i-{p5E z+>nc`KYObR-iSI)2Xdt5ID^Yp0ytORRIHGC=uzAWk1ii7*2Ss0A#Xy8Oa%MI0Y=%Y zRtV$Be1?Yu0qF-tkeC+1$9b{fBIDa(_JoXY$3(p-n(lt}PiU8JzVo(SbE^A{3)N9S z2EmLxw*N_OlIm(tlDgllAScK2_U+q(Fo`2#@QM`p1rmRZBzKN( zq==uduWXF8-_1YOnSooli_1%_moF<${}@769?Ge;ikconA*u?JJtwJ7_6BkP=&i3$ z-#_v?Mkscbj%BvGo=-wd)G_jpsGi@SrJ^?tD#!4UJVL-EA33#c>(HQF4aA6g5~S$n z7zVYw`km@FP!@ZymNoiuV>fg5Ric5KhL5HT9XVje)o1%f3N)Yy&u-X8a)LW>KcQ;2 zb%U@3ICDbr76KE~@@)YjT<`Wx>fegpwdV;v&jcTo?_YA+xe-=g~0fEs^wT^l+IBR`g<6M%F zmI<@xA!49?_DQd<%T^>dGYWP7ROOwyNfVQ5($XkQ4?^RJ#Tb2v))ISCYwM*C{wX9> zyz>H#e@PmX?V~FzcM^Dh){}f=bu3N0cN*vdf#=q}p_5Znx(Sl67?B44EOR5;%S;n= zcM*7%1EluVjh|*srp|D!^~`ElV*!hjPY%~IB4P+hKcoRcE`dFMNs^J5lZMTRe2>65 ziuOxwNTs^N<_fFP@X*jufB*RSD8rstF3!ZjcjGK|JrLpV-Y z?^$=RIPgH=`S0Ivbh{-xZgrgeQ1*22xjZ>J-&k(2*tJXe-Jg8V4++^+Ry@emFgZXD zpUBNa8K(te8P+Mer0BhR>=@`!eUCQ zKlR5%44%+)>Fn$zKT2L7!Wyu41HdS`QD|^AcgorQ@B;%gY{2 zgj_j+EbtQv^9h+FM@BrK6c;;ZhOZajE1}xH%mHZwqj+&>S539PhikcjU;svrApk|) z=W@xg;fh5~UPCWI4;Y>=RV|RSN^0-G54wmz%9|M)b#2d|`yD#OsH&>U?hTridYQ)O zHS@uW0kcFwrhqa&-MZBSl!ca4YB&70)AL!ijK`I5sqQi5JV!8K?O?`r>GnzR>2Edh z0)6SSwVgwutzeE6wf0JR?gXXQELcs8~j;|E6j*wkE3`E8Hf=>6&00nri$2rHgGdE$Bymv37#WSF)z+LEU3 zEGMN=^UU+8>Ytt@u+h_vA&Zkm2PoKZSpO8|mlT|{&sujxL(}yaNvGK5kn*i6?wRQ@ znEG>)=2*tgS@7TDSf>_Mln;GP=pS$PTssL)?w z3)!)pr<~!S)D%|>=_`fzUhSnuMcI>5^$PY@6Fs$!jSS3u&MSG<|4!pSr(rZEUt1$f z6!ER6)a~GD9v;;_R{(5vryx0d_AE_JctGe|)rQz@HjnGVxtLwkv$8siwGEwaD7hax z&gdPx_i}wG&(e0!9g+>d`}&Xz16=I@6S>DvcL{r&?56-juDYIJ;{r;#VC!yNyetXo zca?f!d*p)y*WYd&4+$KdIQXH==k@DG=x`ELk~&aG6Ayjz?4Y51numv1(r_bDu_6LY zq~)q*n;Q%Aw-`NPl}>wZu+cMNAOC>q@8uboJr%QS-ohh6=5||PkDSymDC7D&7hSw? zAtNf8P@H7gi5d0)akXElV|`oAg>B(+uXn^nvcbpzD&}`fGL}Ws| z(T(kbch~nvUCVm~p3e=Xo!74T7Yk4aeb=}r)!QYRfJub%4=qf*vHe!%3yWLTf%zun zkaWJ3CuqTBdLJs``Gg;7s_5v52u?by>+Akckstm|L2g+lrTY%M8(& z6nVaYPeif;c*+~eO?;@03=Hh}hBn_7WL1|^>~jg|2Gf*TwNSA^jwqoS5`)pvry2jq ztw*q&=KoZ!3qFd#^Sn1 zyQsEr>0tSuYD)|6nqG1Ea*2sSxy*@2^wM_bqTg@$!jHeL9H=i$(K%9!S|b)}65K{we;xPOJH>IURApt?NQ zjh^&$rl_#k1?j~7NB5a9r%|@0@ipc0^1{5_FX>e^VREeR#*{qk|0ejfG-Kf&BELYk zX`wxbXlTmxG;F>e+Yxc{)~)x;qsfm7?rowyULBydx#(0}Tnsrb7?RVSmgoL9OCyWtLlP8tL6P!1ar}!~iE{aYvE~%6)rl(t&nx&&d&(w}E79S2k|!$fb(Js_Vii(* zKENoyyxh!4Pk$Wc0W2$ocz*UW^sFO4yYU48qkbX-km8|CMxvwDk#3)Za}1GaZk6Yf z(r_Q=){|7W>o8A4)t4xte?J4EW})VbenE~h74;@Ns!6>W*oB(nCAQ`^-tjuxVISOb z;3Hyq+ML}?`*e3W3jaa74kyY!15EG?5B9nb&d2BgnAlP_E9mOzxDKn6KcN~zUI0m6 z3(Vv#NhV02J$Hr-p~|-;BH3MT`<}ghE2C6L`iwzNQ&ZDaN{UmKusX|%|98^xk&Ix# z_V?@i|J)4X|1Vcg$b^d7Few}@*BU31G+Q>_t=Zbz4yYe?sfzXxJW6a%47YkaWsrRk z;zbne^PZ3CEtR_`D_i&!D{iWR9PKTq8%{`0Y}*tnWmA;p^kc{bx=O5}+rG4yXCmpx zi4%~wWXWQgog=PFuA>C+D?-z~xEQ)} zO7|QbG(M^;*dd1m$1zDh<@)^(l+@JJZ_kS{z$5F!ERk=SK}#~be&eka`RWImsojNe z82K*$HL5B=-Dv=FPC-FeG}f0P1>=#LaCoFWvhUOM^phud_?(+ATvHVBaS3SSE3l%c zxGFJZ-4^{2H2jgVa zw@9e3J(}oXPxR^fP9WkP5&)y({k+E>LWZK8Gg^?P3!}*GDtUDU0Vy2Cl^Hr>&dyue z&Do$gitQoH2Zqa+*CtCo-ys>BV7Qi_mGNR`({XLzKH}JrZV8)jNZnB@{A=e3b0`0O5&39NRV-=1rgZzZMX1%$gR^6BpU?_ZsR%AAkb+pkq$34qX()zpucT-Bmf z)gp+xl0v_(D8ypFL0JTD*y2#w&BQ;;r4dL5uLXO(M`@)EwVx`glElp z`sYU|umL(wkh2iez4=VwdZXO4Bru44dqPb5$^qyQcs@L=H*r2Xxl_TUDK3QoY{?OG za&m&NFPMW6Aa^|oBTy*rIte^$myTB z{q_VY$n;pq`dV=?o1|d_DlbU=$!TNE}7-0(^ZR z_U4MMUT4ep{3Mj2yOg@_Frk$03uy?@LthsJDOrhI^-npUD+Rnk@eqF&D6$q~_+B zxTG}K70U&~2xDnt5)PkGS3E)1oC{V2I%)#X zYrJaU;1bSbFF)1A=sIoGm9LGfu(GmUS<%-g&_>EkH|&(EcBm!Hcjh67J<#vWQy;&Q z9~KbM20t@e*NlvegHboXkt}6q9XWFNci$0+G}5_(!>^vBAP9X@B}@A?SR1f5Gz8zS zJ-hQYVxkL6-Q|XKkeGo@%Exg1RgnQz=t8GD8OHECdI z$a*%A-dn3*88EV%5EaKrDKilsyq}L z>)YG&CDPPhzGR0s3Y16LONc7Jb?S~b!}WmLZ~K{V!7stWF0xxN7$MT154?iX>g%#C zSdKO#K1P-X{S%yJ%cPd(LvHJy-6C|+J!xf3uE*K*(&GaZGzFdv+SMb3yA$s4``53? zA2ImwXZJF8^Va>fjz&Mr;_z>Q=iT;Jdyy({UgA1mq?4iy*N^MwgI-n~BgZe6*y`w% zk1zE=ME&7Yw*$~0SajuBMJpp_M~d)UmnEJ0)*h8MZgc$j@fxS84QwoXX?frAsUJDD;84<*pP{u7=RrYzY;oip4Y>55yP~SzGWym@ z8Fl7PAm6`r%hk%I|JSdXUw3G#2WHpTw_o5lXisQBmjldgQJ)m%}%fI3>* z@JosjdtdpA3_uZoaA?XJ3)BnfztKKm37XfM>?jajvsxd%qV?n{7cs4TiWg84G6nhh z4pgPz>*^-+dc|S7wPC6+R_3%pv9{u8%*?>l`j^m=bK-2QtX!blo#UUKU0i*%`K@Il z*>H7fcxDuwM*GRuLWynCjZU*_bHeO{;yw4UFWA* z9}K}3ZOZXGhDi9_TW>0^RO@hFmY};uok-d+7E#uEd~cK!tS34+Z7N>Xh2AXP+T@xD z=y!Ab_%YN&HVH~$ek8Ae;9DDsCmv6dYcd{hE8D`Vu3PVv787&J;0h~i2$!|m+_6j9 zMI{UJ?J#m6qo%Hl@=M_NDYp9VaIe0;zHRd<mElo`u9(HC8jp;^3(}_}zm=&x~9*d4l){hSeKKiU@%KxJ5(Sgx zu`xlEpo4VW5X$^cRMeALW3a%?YWJ3RKTpa2&Ob zu`gz3uIA>#V(DQ+W{YmP^XA~IkB#pL4Der`8Ov=D0S>h8>t zN8oiB{=R13!z`Uh-PVMflhVrrT zaa=`(ZooX-*tjyQu|4=6VOBKL!FeVIa+w7M1&~7V^zvY+s7_N#mRD2^j1M4eMeh5l z=jT=TWSFwODfsvnVGz1{S_tl)(cm!;KVnVWr_@1#82{-n)Yo0MR~#7 zyE9vVZ7{?n*Qkx@XWIn8b;kryb@$=j{L#6s99udb(rr7aaY zt`Rt+Tg6UCKd{=)<~%(pkRmVY{3teGZza2p+@iUciBCr{mv48;0*WRIPitk)c%swZus@=*B-T=zVlwz78WP3>HTa| zcZ^m2;1!ewKs5%~dgk{t6k~#eLYVif%cACodd8hw@AD6l>*^SEq&lu`Zmindt_>gM z(;3f)2BYqS2NzW{`+t8W9vmEO9E!3vAM&m{?)dAItyn$!o%Xxkr%F}qr$0PifAVB? zVbq6;qYkp9z_1@Wbf~_MgHX@^8U81K(5<^jzdU#7enHpw^72AtM3AIHsl#bzMfcgW zopu{jLl4}aJ<~UK?#g%Kp{1SK;56U0|75;pr@zWb9tjoqWsUV)=(Iq&Xdq?DasO@1()~s#p)+Y zOUu-Sz1W;|r#WeGZU6CUw|N^8&f&&^qqJY51c~#Ex*2j}V&cx6JGZ`Gt)sxf5p-AH z?rK4!@wxNr`HxC(JayycU0_lzOwcEtnDscQIaGJY;hg^ODfRABJNRhLk4zajm6&oE z17tbcp7AzB#R!4Mk>>K=-mPCxcSqm$`p(^Vn4CPok=cImz0$_&l1iBq)zep!BqHiC zxVeUEs!x&CK>?U<3pqc6QkJofPOfwBrf)MJ>mV{OYb<1dbO+O^DnDL8%#Ygp{K7&@ z&CTy@r}+1nE>|3)b&V7_bh1l$&lR{XU_(y)T-*Nu1B$rHDlLW8rVS59e#`@OI@vx4 zgEbF61i}Z*O(C&cRFstVpkQ&D4~-gi0tJrVP^3v|V$kQGu%8kZ6QklZXohZ34+ZbN zrUHa@>X06Y6LWrfSX^9$MfSLO$f9xd?NUOsiGN_)I&AlrPcr;Ikm`+ur=_K3WqH1S zExqTLQk#sj;LWrxVAj%>reUOG51B4w`T*Y3ZKbOR1Xy=_gA1D)VltqOPk z)=wmM0((Y|c`a@i-MWQdR9K0<>%k5VbL1x260ERx1N2T)AUE`?PT+Y?vVvjSZ^?W2 z)@xz0dGPU#8<@NGvD`n;&Whws3OrXW+6o>X`LsfusGlejD}DV#_+9;n7hUu1myDf$ z96M~DtlHUBot&RQ&%JI~ds0kb5AaQT8u=n}!}3MB@d5ExYm?nvmo8o0p_1Fk7913` zb7#(rB4iQTp&G)kUpqTwSrC{c*_5Ip9>j7Cw63owi>7$U zHcHSRk}rVq$MQ$gMI(T8x0o(jI=_id9AaW(`pUUc&;H6BvZaf@mH-(sFv?2g_H%M} zEzoLwWqX6|^a-?5adENe6c0&BXVEcSZ49fYWKrL?v4BFer6nESPS9U})+4R{mN<0l z#wmb#M5;#3mzf)k63f{c%V-8($Tl6)?6Qfwmh{Q&s%%%JQ`P?J1z;-m4#ea2;kCgl z(9t%i)Yx@Kw7TrcXs5#Xc_!wFhNw|9U^z->P}d+GG9NEF>zI4IY~W_`%K54LR*LL{ zfOaizp7FJJSx^J54;R23S*r5Wb9TkN5xU2e-nb!G#1bLV(TXs14#usAD_%0oJ*89> zqE~-V_$KVh+3hny)Ym?J0Y7C^Phq$XU?))WWl0PAC$pOmlKiQ%oYkyX$*;BFVTkNx zx0uSVp9genx`qrUztq*c!+K^50h+YY>{_^X57sh8mKG!Jg;uMk>}#d9~=| zavCo8gGzX^7`-9WNy42s*&GQD#;lJ4pDI_*WpSv->gwHC^H9(z9AL~Hv=aSdNR7iE zo+!7pG|RuVZ!bD>TQ}aB`_<$XR|NWE4RsAD_og{twm=^WeL1gm<25pTSwi|#d2Uw% zK|MV^bc%#>#dlAos3X~oWVKM==0(2)Thc?#-s)ssW9>E24kSfGLYs*@zsY%Jj0}{0 zdDisMCX6#QhLI3&!`}{NN_$L+Gu?w&05jEQU?kwh&S(Rt-RgapTM?8B1EA8qB)&M> znDzYg;}wv-*Gn`s6f29iHy5GY1+U5zL-!&t z6l}?_yV8Egqy)a6&)qxL@E+20uujz)hB=63S_2ztdL!W@6&#YN0Su!C@-4_ef4!=W z4-2cr6?9E}5FoB_3J`3+>XY3{-i`9+$fc#FD=2_rwSfW_Za==@>G^qEJDkwM`i8Ry zM;EpMY1Bwka00R(j4drMn=G4s>0ZJP4K3H0u5+uabsV~xqzyl&&(V1+T!a1+D9E*> z0mE;=^0Upd8~u_+)i&2xIWK}QTM-fxl9iQ3-6HNEHpbnCAy2#4*lzl_oRPl+@WbZl z)}#wgDvWXz6}g5<#jS7@faYW6hTZHlLCokOV|`>1=3`*_W}tIzNKU zTXSZnp&{h);~QK-JExvY`{r`$xTg#Zqw!J_un|b<=uAmAR;p$1%bo!Qt$?bnqf=r( zc|2I;;^eg2EAh=!1^ZK-~G!EjtS0-xCu?9GU6q3E(G_ zqGAgq_}VFyCP36pz^#Hh$a{DHczYzTGC5fb0K1In_|8s9%t1e(pD!Dx!B)$02fGds zl%mPX_;{rOk2TfJk@o;u(s15{CVGnl39}q&Yp?7@#taZ3x5dvOJOoU=Rsy#}9wk908u|jay{rER0&bus5VTF);yg4LmA8GB7X<%4YfDJW9{XcmwvJ z@eqeVQlTsTRiN5=)YLDF3no;<>_LH{4-obz#>Y9ixUS2Lq4}8azB_fc6bT7QJhXuz zjFHltMOoFJ;fYYBQUIb*UsspjR12QBAlaRe`5`uJV(+3_v#i!Do5fve8O0z{n{_&i z5(UMIi~1h8+Qk(CM%{J!`Y$V;{Qy>MFTl43Jqg-+>2{7Mp9RSwuD)4Y%Fn1RrXA7h zpE92=X>HHaw6faWX}mGe*1n7T>kyW%62lE=a7udmVh|%=^1*cicn$N}-wuWQpX`1d ztGR%3uwrVleR&qDRtcvniX(Pt@MZJhPiAuRKd`x#p!a6d3LyVZj!1JeGd~>IQU+b`uNl5Nq@&2R1KM@%|`pqI( z-1g|2#XR#N9Op5Qn`jTHPY7q>VUFK zu`n1FgJhsm3ySu0UK`t975%jcDuCu)qN_puw}$s5vJ+GnI(z466dB(COk0``fgoaLf&Ob+1g#2&Xs{A z7`ZPx!bP+6Wxhkj^5@SV=(WANICh5i!jVGQ7Iaee3ZR;u9L$(iEY7xpEeuXKt_UV0BBoBE)#W7%g`ij^Dl-=DL&m6F;Nru&8e24q@JhTLS5*pDB}zWN0O z^x4b9?v*JR^4C7|V_NoYtPf#wDLZ?G@BslF z5H`pv28yFlkXKZ&??@-7Rv!3OR}ZF8n&--`^<7_Gw1<+A;SDbz^z&huOo~_-WuJsb z02%eS%^6xcp&1EyENpCSmo%#2;4f^ZFi_SabIR?o=*}s}`ma>4oSe1Z#YIqReF+7( z9Vh#);T&+CRWD;wzp&^Ih-}}PYDhbCfJuy*)CL8&)Bvyc09R2N_o3l0cog38u3MrF z>)VQIL!y&V9L+i#${88O0O;o9>kZfiDfc0c17Ks7vyYxfcFuTuRR$_oE)a}Oyj&$s^v)hAzx>s4= zP8{s7y(rQtRLs+7R*@3*t2%W`Oz!^e)bT47L?x~JOL4e#I<0{kfMEXZTd{1w!ro3u ziY`i{1)tF3LI$B!(*}^thHn4f! z41ne!nyInt$!2Fy&*AQ_6C`?|7lV-PvJh=DViQ3^Oh8CDD=tGQ2nEi2nEYMfrCR%v zd-C`1neIMm8JVEVtFWj%r43%$eX(3Yg|+^B6Q;q{H8rsAm4J!@xVDV&Rk#Q{Pu}Wk zHh>eCSMfl!z{GBJ3Wsf{&D}JR#3~eLmpJYuosqevT;;L+Ql*tEP&AzB%(l>)21x~7 zhJ`ZDqkXWf=mckq?uaR5#*T$T(xi0|;%2XAfB2ADXkmdx!bbb-87EY$xRkWC;-~|^ zE3K!FHXKHBuR!G+hoUYh_!`)lcNQ}bIc>a;jj}`;zN^aRA1F&2h-9+X4783cU2*#ZX<6ldjNA?SXA4Nz8t+)j2l=*{-#Z&L_O$}J?r5`uyR3&*JLJOQ{H2G&|wSZK~@LQMwZfFv$w@gf=6ydfb`!n7kWLbH4lv;kN3<@x%| zM2MT{;(kyhn)H^}48^NIjs-;=bndmG-DcnI$H6hcAE&kxyw37D+7 z8YAU)1aAmfI09UIzR__brEdg&kXS;3Xjb4Jqf&$R$Z-MC*dY+>fd8}|aN&05*HUq1 z7Sk^M+tV&|-pKkfF)YB)%Wl3ZyMYIS_7!K#%;V35NkO6u4wo}D<(jc?BCKNRF9ml>3&uH zqWfEVy57mQhD~*yY2`M6O|)`3$J_3kh7l8w%6)J_V>QB82wU;Wh0D@?*{lqg5}3-F z&5q;DKlEeq>hj@**YH6gb!{6^`6%j;5?c@p7_Z(Cp9p8ls=7~`sOf;rZ# zcVY(&+2|6v{)XH-deAi>`~1wd-x%GI_EbW(hQ3w2>Gm72XZ+@V03uD9B<9w>J_Z(+ z1Gvi*yno>$?^S5Jvea!{Xb&|soOKmjnvd8VSJIe#Qm!><22m)kuevTtSpe{F$v;}z;+yc7)<+j3i*i1(c-gr z&~=x2vJPCFt*ve2*>b$69KRI|P=>=AO!fdh-a8}IGLk_ZPjkhAGxW=~Kr#)a$m8EV z>Tz{?eiy^8i93d<0~;4#F#lq&eMRy7{u{p}FI}nL2xCE1U|GNc=ZzK#5fSeYw&V6h zj$$4P7O|1Bw)6aACyg6=SARF5AS*ywLzEn>m?STLc2BCIre4loTwf0LLk&P%!)bRe_=-oSg5n-bvgByP`XYyK6F+T$(PV>gZ3df?rFiHlWzSp^8*EH`Q{j^aE(x) zL~>}nofge(`lkU=EmCi|Y;?Rl>P-AQL1dz&6y$*~Jy$CzaA;Si7B_Z(svgm<{~w5QFi{wMOCB;&&o22>WPgsDKPX z1#H2orOAVZ^9+({xCUB&e$blscaO4{|W5k_&60ejqAWqtDH$ll;c2b zNuAw0FDwB%+00krMs6LR|g+AnSP5k5?~zk2L; z(aRBrx%j~lb|$m)AUE`w75tr_P3F$(yuSz~;Q2YbgQH`AcmHg)=?cr1d9&|P0}vsQ zbd0QzfSw9EVC-$}O(*gpiECQ!ZG>rQo42p6AWC0Ha2HA}%QJFU7J$8^NTWT5V> z_e(r%mhzGkaE9EkvFDF=x7&y83S)&)jA*wnQRZCIX7vx!n07M?rc-ls^W$xigaGh7 z|M0iAT}EhO4s{sr-2-PzJr6JMSpF5mei;9-NqJ0`5`ajccb-kr{@b35cAthprEbw$Ur1CK z(8)s28>F57*dbtUVR`1WDpnZHl)%(H=;_)!JRCmk>Fc~+O@mQso~M23Z$SFO@46hU zn!Ry0e6WAaKu@o{yGA34hVeI6|DA0b3lB{RZS7a!V%UUy!D040C6+@(cl*K?`~@b< z)hf@AZrm8Ifj7cvCe*C4D?aS2w3u99+WMOy@?Sgou7uwNm`_$ZyEspaH!8T~cnvmO z&If^!BPP+M!QUwo1Besb?VH`J6Vow|_T9&qjt^+@5?^y+P$aoco-B60bQ;Hb%>9SzX?s?)|y;O7=W=24&O) z-4~;Gc_Xka9&nn-!!2`~R`|r42?5-BeHctG9k9{v3gY1tCi6L)%zfKc1R(_pM}vNz z;@g3@`Z%AxaY0lvqL#L_qf&38FDEw-x?U1ClP4jZ5LG#y_l2MlaXH7lTotnUd?e(V z)#)smydR2ky4u=JqtDf%JxUil8)wQ*N9BtY>s`YhCA(h>EC06YrBrzK>=_uHo~|4r z3;IJK>HEre1@Qw1Dm&ft;PvBU;6=wd$H_cTQ;%zm^xvwh^MD=aM`V=0(4%>+gPg92 zNE>8h?3UL{w}-Ed08{~SQrux59*Cu21Rg2{fWM%szXBc?#N*Shhp1>+yjJgTSfng# zZO1~Pr2`HOVA9UfrbqKNz$jt@7EC<5`DmFj3x$xn+a;`UaAi^~(A?VG9IP;}1^5?i zXqAg8&z5^rU;CZ0TWn5NfgGr+>J*wdv^=k<#+kZ$OEtNT)N1thzC0UJpHk=L9!~fixy33>=p6@e_brC47F$atquOe8}r!*Yov- zWtc~;X8rm0P5k%mpFRgc1Pm^VOW?1B_|PS}Jio0lz;^O(@@KiZ)H9!hc@dcUGuXA?x5a(4sO?s* zzP&lGW2_w>WzWIMnFCqG+GHJqZPWC(LS=V<_t-;g=GdO0ZV3ftr-il^v&Ai3vsf{I$=x$)6)5)27DEZMg*g1pS{@YJlXi@`2yNCnwy$N z+o)-1Xr4WL<8s;kTUiBM@Pa3a^i>`MzC4ncP+{TR_-7ns zQ=Yq19^gWQKrHzq)@~1Cf9@L8qK>?(vH)eev^&g8eB-{Ux7r^rNey(Imsgr@vSvNN zC|z@;f0bE(9|B8;vIDmTP${4e7W4=71g6(RJkNhP_;`)<;)F~VG$yOXY3ZW>{p;`o zFSgILKFOYE!UYV)8Gi0&K5VoS%@{{rB+yuLtApTj_*P zxoE|W^X2h#k|qumU0ksIh#|NGwVx5DHhX<0E+bJ{r0sb%QXq| zKmJF*>;LVC|J1Sn|3$$4f4;}xJOBTpuh|!0LqOQ(#6)(0>R)T;gZTRS(gD7PppW)H z|MHGTAnZE+)#C9#zb8)_Eby1#{jbLdXleP^|07n(|Ic4QApig3lKkzs=l&k>*!;n1 z8pC+B-W!XEDOX0D%HkJQy6-UWU{ZV*v00Rx-Po$X_HeA0_^HvAVY5czJ>%Mrf1+u< z6aAb+rKIbm{gbjp$qOn9M`sUDl~Q<+E|15)LZ$G=75uON*uF=g{qGO|{l~o@k)HhP zum9&4SyAqM{+}28>!rUQJ`nitxA@ne;0pdfz1gc$f(gD&E*@6F)Q+D&0|iri`uh4} z{Q4^^O6CVwS<6+g%tx{AUf%k|Q|IPVTkD^^oixMefpm3M&y~16r-(UCg6>0kZycx! z6IS9xY16omB54>tlo%KiQ6?fqW1bgmLO6*T8TeuCD8EcuRnp!F%S|#`CKis*Ln* zKfhWo?uMmx3WS)rw1if1Zega2`U{Z^IkL%XGpp>)%eDJBwVF6Xx%MO#{1-aT#(Rgu zU)JPkqljZZmsvDFrn9wSQ7S|W^Dmy?f-Q)L;5b8VipI(0*e5>HI5-^iv75xKe2 z(v%Pb_C230D(tI))n_q}^9}wdPpAkrYxCuLdHm16-7pc2=T-7FXmIjQ&y1db-`FQt z!SI&Za{Ab$H>#+B5D>C6vzUpl7+r3dN%GTR`;R-N`{6N^jR$Nli<%> z+Ac{J?=DIevrrqCa~JETN-f@h5QZ|O7}!x)f2w2D;^WP>Ae(AMIq^7i-~Re@MNL$s zwYTz1ryk#R&w=I)A6KF@9}gxIMOpEiH(GNG8#l-N*B&@~k4oq7MKYJ#GHCI*I?X1b z$dL=qqFmMUw)%{H)0sCn-!e2XsB^nIcd6-ZaQTm=bk1<9iSk**_f8N-QELlLW`VMT zhDz!fNmw93>65#NK=i`-Q+u55->a*6H#<0J-Et3GA__x~Utb)vj*jtdit|2{q#j~q zdTFbV-TqUjfhTXw{BZwxZF}={bK%4f1qDf9ef4lLlrTYEec^s2LlXDZ^HD+yz0D0q zzWRZQ%@r~s!(TFF{B}$8&b^n&*`Pi6*P=eOaxX#_Ls%^@4)|v)qZB`(=PB8Ax$7LR zyuP|QpE zhMs{?I=u3csDj=Q5$7r%O##{L@j!dW3P(r#TOYiH*4LL`{F-%4E00ZR>TZ|O)5SoH z1?|H$(Q<)58)U47vcn_t5vAkY{?j~lzIRZ9D;T1=e0_z{&4pA$GK(s+%F=(~+9Jj_+dkISd4^|lJrcC|4h_MkfSAPR3j&+&peM4y_E0aS9dw<8oj=QS!c!OqM|O_H8p0OaN!PC^MsFcm z^U%?CLFfq?{l@a(?%QGm4Ea0-eJT$ARx3Lj2RnyE%OPKkX4R*MM;P)?+ty8UJBa)% z@4z;TicB_^B%pi3I@LQJ*=i6LMtA4@A~-a-$n!(F!0?o;jK>5?s_fGNYqa+^w6ODx zgucYb(*(7~eSKhQlAV{A!@iXm{O^duyXTHWj`X8?i00cuG{~R*L|Y%sQ%X|5BOpRX zC^00lEJ{juvrazDl&3v$ySBDp+RCAy;;F0PxyDOoWJ-U+Ad!>%^kP3!V^Pr{yg1C+~|KRqAm+ zv59-VNvCT3I$X&d#Gk`K(NTT(QON z#KVWMtC(f-c0L{bbk?=GZlvXg==?djPuO^IkYSq@Mqi_*U~0S2*LXF)d%)p&NjIzd zKCX9Yk`S?Ok{dFpz|xhwKj_0Tx3*MD%~6#8l>Zr9Gyfll&F8e#e9vu{+G}ShRAZZe zrp@1v@E6wPYk((0R#EOWBy>+q-QIxk=;X-ba7L}UxiUT=hC!ycNAtBI6XvtdHI;Vk z&3d;zdPEDu8%*>UWVfHxP0v;eAfA~Xsg{a9LYU-sVO6pxO856p-g|^E(a;*5WuU0= zW$Su#*4OBvwNHO#fvFM$vCad`JGNKLqWX6S7BM@G>1eyekKL||2b%hORCRR?4OLUr z`2_#@yoxCTcebEU67h_}xVqBvhv-hDIqGc{jDNy-%e^kAg49aNDzjY2TrER8mktVq ztqu1Y>g@hW2mz{j>bh>7;u%%`W{av z?c!j@+A0s024WO$&mLq@wBS=>$ViHFdM>xPka>z4629*HdfIY5ljPZWQbE!4XM3sC zV&O4@iRb0%82?q9Q6Za>WB*Znm(3VYK(*01&o2fCv3a&1dHa@FtV*76g#+o9`6APs3L-Vje`x{aY*bxFX%SCr zHOt`o@-WAt9>&>k52L+C1hg)j&72DfeBRrme^ymt*-yCmnIe*N=Xs87FwreB52Pj` ztX|sZ4CD-$^GhRB!(!OvFJgPzlO|qGS@2FL`XVCo{8rM!ENL3mkjPC(CK&n8z84-Z zr!n$r$7;Rb&ARch{D`=R@cDgvKgaIm(Bp6~tC}Z?;+@-k2}EMD`jg{ZVYmM`JxIOL zc_8p9r!#<#usjy1X~qHSoK`?sxw#{>JuP zRHeS!YYnV{Pn+c7d{@ncYj$nr-GqVrMcKn9fFa}OjY8NQ&W)W;cGr6vD4mA<g`#r!*FgO*hkNtCXZgVt6%u>Gq=&m)I}TRPB+cgKvv@ zCvA6P>D#BguAFCTDAwZV=!8lqS;_8eJ2yLyfnfSFINy+Dp>^})$Dd!zZN6Rm8;JLK z+?T%D3c1tCotg6aR zhb3Ri6gJo;C4*yP2nf~drWooQg;2kA2XaUn=^{kXDOY2mKg{KCCh+&eXf2Dkd_4=1#) z-}|rMHQU@&pXRYB>s|B4yKA1=ACgtccz3X{ps>zuZu6@;LrJ+>ble=|ukP&_H*QCa z2Hc%@KfTt6^WxhSSs6Y0L__v5!$KM4JlotDu&V;+P(mRZ@5>B5i$g$Qs?7$~2org-6SfePyq`BMk) zbAsm9-pAB@);eyN)qk z;V}psr?OYDq6FV`c2N6fv2?e!v0JN{h`PpS_(Z+sz@`nkgNTe=Sd3hnTRI>`Bew=F zg#LIlpNof**07lx@j&URkzGw`P<&~SnzGX{w`D_N+*<~9)W}XA`_1nZHS9b*!&AyP zQxg34b`G5#ng=6>WaX6=WtA1msw#Kx_#GeFN8+?{NTrQDNbC(yZECOJ-yn~|<$qpK zrII(cRyI-Ta6SFY#B+Z2W72kLfy^~IH%(9X}J+IL8^cUffyI2dkFG7Eafq{3jTw=;&yVIevkCE2Q3aCfVurUZ*p+ z#Gb9iQmWPF2A0S;)=RWxi-`Efk&qb%pc+w)oIJNl6>7ksMv8{4G%lZkRT!1`OrmvFwr>-h_ zqc2qQ&*O46cIu^sv_(aHxh%?f&G#Z=!e%2{mQYT%HG2k_Ok3COg$|9zYAuP-EzK>? zJBvJa$fN1ssQcP>{4ad8>gs>~oo+XgDNSDUr7b!_j-_N3(-%t3`Q;Zc_%u}%ZQAXL zFsXgS2YUKw@pJ`xzRk_Cz2NgW`>A5X-unA@RFEMOIpzMb8G{`$K7t@Ap$*kXP@~?$ zON7Ps@Wk&NecTrY};S`VN}Q2K}M@!}p)#^BK8nCeq?H~j`F-{ZfP!mKET zB;s=zW`7I?w;@DK?y?g)-qjES>z8H-7>-oEQs9}UY{rheaDREZoR#hBtg`WR!P4Wn zk>AyMjN1~z8CP{xp?c|dsE?$SbOOI^M8db&L@I2jZ2EbNw5VBD>d4!O{kiz&OdnAp zme`*C!Fy?ZWD5BDkkGg_lvjq$x?6qjf+-JmfD)o@#!RH}a6* z1{LvhCHA)AUbcKL*rp;L__jR3)!-5JT?yt_RR4;D;Pc?neI8!Chp;-E=S&L-pHPjb zlaTl`YR$5`w#_UQhWhSZBw>HzKaqvPTLlHpUS1R>Ryx75g73v11ob|9mcW8Y%!~Ic zNb~}|uFW6QeTu;~JHO-Y(KWlm?MD?3*aj!O#?CO5fXn&t*WsbgiXaP<+v{J0%sU>V0HJ~lSzIeP2xscG||f0t0RNUr45c3b;r zE&9)(w3Sr<6jH#8z*Dc+b1-9&AtP(}v-}SxbdC)Cy$pxH_`bRN1^Lk+fat$xUZmIZ zgh(!HGSceTDkkEqLf-oU%5S<46E*sixC~gQJE{bc5R_`%v{B+o_on>gYiSU>XQP>= zIKU6V%JBX7;m0uiT_hi2hh7z_{YiFDuuJ_~gjEk=)eO zj}z;(X+%3Kugfa8Z`Kch4Q^dTK`_J+J|vL7l*$@tm20Pxh{3@=)Zntber>}@)(Dx$ zhVWS;DTic?%}at^Qf%_O&kI=eTd4Flf|kDk-VeL)r`7oOXJW51o}+N+&GK z!VS47Sck{f%T(`pJ&P8@N?d7hwj{A263ayKIO#I{1 z5&Vg&udonftZ7130B>a0amDY4fF%wB)tizlv2bJ^&EfB#lhwa%iZv7p+J2;BdRreb2#)q1cj;}MY-0scm~V)&W*$lBT#I zk6lnvdxsAt8($IuK})k$aoBwA{Pr9^WzbW`=j=U5B35<|sc&<-){KXg?hLRDK79dT zoY-nFjjwbO2?^=eX4TtwDi((xnAqXQWyAqO;;FLux@nm{N=ng1Jt~$vP%(ezWW=!bOo>o4 zd}^l4z?Pu&IRaqlO1?czPT{PfC@sd=B<7**HyLtDMbjyAy$|`_ewY~xEmW!VS?*-O z@Ppg=(^Y53zE9;5{-F}6m{=@NjvXA`FPpd>)tF;b(Q0=m@Y8-6DmbqV`@WHopfluf zEVV{OE=}Iuu&Wt(Q7xtiMhrVyz9#{lIz)+5h^K%|9MU|tsK-?i@~8i4hNhUVw(|(E z667DNQ$Gq~3zV&q1YU5N)QG*HML`h6H@{~JI2$DJs-kLd>%n`;&V`P6h#~Qs+z*^t zf1AOCOaZ)DfmGR2#Uc%IY&>Q+L0a| zgP7QaxPK7nK0kGe?YW*0ko9fibF)*UAkw-=HiL2*LH_qmDtry9 zt7^RRtaShbLAi19ayv1fIZmImJa8QU{S+bl6t6G}|37G&Lw7Hv^hxw0P0bn}g{OE( z0&7#o(jC$dd711?GcDNt7GU@b(fym|7|-*5rJKRAAsB6elv0^RcN2Jadf)j6*S7*^ zmnLZny=QB5RXj6)d8SAJ;={!;MIOCXI~+oNN7IHbZBV%$TsEw-rGv(#hQJ4-wh&#L4|(5@LY?GV1ZQ zITg7PQ!b|KGZShTuCCIvaTDGm8G8i;8v8fOR!qr}Q@>Whi#-^GN{!UA6o-9lMe33%Bq135&FI)>hS@$MCO~O{f$Q zAi4?(%gb5gpKCiA?RwA(wD6&zY+E52u@S##4(Rg{@fWJsw4CTQox5c$Nu6l1tRj^* zgd|WjMARlzT2}H+_9?~*%i~qMnv>aUzqdN0x#hlJi$(H~5Kx+Se5^mf7sOUb;&Q0E z5}|X>(RwedGgwz_f*@aiW61OjkJfpLsZ^Ps;H^1)EsVTrmJkbhjw-f4sdw*q z!M6PP()0W5saBE4A8&GiNY_awg<8FigOszEaml!j}$ypfu!8qu~E>z4)%(kZhO z-}~!Bo@&bQTS8D?%Sb46%J@`I=9RVmNHrmSnvonH;gO~_Aqb*%@9xTF9dEEV!NX3 z<(89RIxjwMCWuzlAl-sw%yH_QV5*TtK2287m|t3XwXus!V8T6Pi#GppmGacIp5euo zh9bU`!@bhtVtd;Yrn1A>nw8_xfPlT+eL0)1qxny>mur@Qarm8VQJ@3@mOWIeh=qfr z(O_lJFz6rNQd7&d+|87HJR0pd>o&bR6xe+=eN(Thpy{&sr*3Qi#2}?{cAzuXU!1sl z{Q0sp+0NweiCF3qPKZ!+ke>3KVxt6Q4VVP?8C*w6@LwE}ZIZS$G+f)4kEHEuBa*}C zQd_57PJWE^A|qyG#YW=AOL#qey5V#Ug5KLUOjd?G#-JCjJQQ`+>OjE~4 zi#D&s-2`wIqm+gT3HTOk{*t6aBLuEy?-sx)$x7SwuFv?u;Mb`>O%e|a6JZl|M8kl}pUH_P&a2xS!Wc(Vjfk2pH)3CVq zX1guUbF!ob-&+wQ#~n1XOT!p!>to<@2pAalGCA5B3$by5HbDRO6~m&=qvO5DD4&5e zG%+yryMschJO7VhxH0|ED|#w%lH`^6d;hTbWxTjhAtRIio9?Os>hFuHnivYaV`*u_9)R}B}>xIP4XoCPh%z#g_zkJpDTSHW^< z2$!#pVNdb8uF5KjV-vp0=E>usxBfJd)=D_Urvuxbut%p8oB2uza#-bNW>Mn$mX2dr zN(&@|!?G9%kB@CMN|g4C82`A`Tci{@&fQa2pAKls=@8Tp$3quReLzCYx;=SlwPwe4 zw)zyI45wyFMlllN@)8-q{@L#vOTL>179UUJdJ~Vp%B4xQixq~bq*~xluCx(Q zPKv}fQ&J+O)GqiM^JG@!>bSVjQquOdPB*vp6<)d&uf25bl{y0AnI2G!7fEAX{7hfl z7xG5dNz84Rm(jukt!=F9ovwq86P82G%(i#2ny!rUi@eT44JCOHtZY*}Nx%`0k7#5K z^^T3~Bmq{dW?e0cv&F*wL)THsPqn~+IhLYwS&-$kun?m}ri_j6!pPWS*tk4s`u=~cB!UM5w_ca#7kLWk$dzao@mnAMnpZL`QBExp zL#%FWA$+m{bRL|#AY?HQe6pr**FF4q32Dcka_Fo!wm!xeYN?)nmhJ}m*+%fTgI zAvy-ft4z>-XB5`BGz^?!0v{A@K3QEi8JXyx5gJQ3h7h=33i8D{U@Ij?d@uWY-`f^f zqJnR)XOt#s@0cx=!|nCMmU|o=j(_V~qz}1WCB*}8MGeO`M>hPeJ5iCED3D$?38a>> zvd>&pJdr~Qu+wp?n@-mX55J@%RLCWQ6%%D@i#3uWn{6CRSMQF@O5BStM-$N6(dY*9 z`Pyn%gYe@Z!Bhjig1y~+01Y%7?2^P_Qj`!PC1rWH+n z!0XxObg#BmxtMk(bQX7tW!~xh_8pq60&=qckqvfn(nNzVU7ysvN&t!*SUVhD7I}S> zgd+Il-gA|j{DSiF?6lO6ss#)TRd*0{ip#i@o+`+lVbBn zV7L3VXrrvOj6`}U9{SS0PbnOx7>inw@f^0M)aD?@i57$Oc3~k9Zel=7^To+aIQCtf zt}iP+3yTWmf>QjmJap z#(g{AP0#5jiE-4@!>;-9&Kn0BDJnGGvdwwc@nwQ zEB(D#+WDS|G%;ZfQ^a1M^F>9xfx~f77{Al{I3dt?x4pgDIEH)s`U0s!K_Z2)vf7EE z9SQCnC0JS`YtS=XK_D>i00KzlSgXxMgxEdA(b`@&yEzY%!PC{%a=+e-HkYBI&N#h5 z;TRoTMdGP8T5(4Rnf29hBeV;)wzH3iC_}2`Ny_8^0Q7NPDvh#WJKI9@mYY zxp@V0(lXrsRD2%ScHesd1)uh}(McgI`vR^7?6-)^$Zijg5Nh_ww=+EX;3jbM(i8{29L9fiFxiAx(2_ z@Ld@?`{jwHa^wl7T;7pz+RkU!`o+Zijon<%SC)_92Nu78uhZQgCYYK4iAO<3=Vz9e z@*-&iIjqEANlbA54b3*9-2pFbZ^65$!dwN%gRQmzl2VB2vPy>vzEIRub=&;K*Zf2P z07A?9hIL66ZSbU z*vg0rOP+&~sB2qm)ecL7Z<^TB5`2^xj!%xiKKE|Y0~iO_Qw_ssR4~=}5q0F+>gLb- za#NhQO(PQTBJao2*{VNClZK<=f<Cx8=s6N~ip3POWJu^QOQCWeRgU~{iXlX6_WOj!^yJv(xJ_+k5_ z+w1Qi;D`|Q^;67OrL%uR+CRFShH~uSFoi&Hg&0&_cjDMG(?UhCsl$czTL+I&eM`kE zn7NKm;9pt*StyYUJTITKnA$@@Iyar0kkkNVC1<3x24(p3sqL(P&|8g^MB4)%qbyQK z8r+5Sq1JLsvbQ5pMwx)%k?@nyE>USR{(Y-POpxsVPr~Nn|Fkg4!?EX3tG}%+x_bdI zSQ#m)8P1b$18a69+^*Q|I%e{G>|Ej&=Ron&Mym*C-b7w%yDdfpFUhW;7eCKNa`Lk^_R6G?M z2S-Xuddg7W8bFjgqTePENPrX&=m1(O7)s6eRQ(ZL3JV?e z7d$*=%!XHkOF6)$*IFHa@e=AXC`Gxrz`E=5&aFX!{NB3#`CRI&A;VKpz21wI12D-7 zv>Ax+<)th8r$AYGAz$HG35gSjSeRN`YHOeUkhnhHI~%<*zgM}p>8A_9Ec@@uJ z&;0V&NmsH5_iWAF+v4~~?w1o82Pnte*UKhiSwrSqr1Z}VsA<~BP6sjvjgGN(;HLcj zc&w*Vm=FB_4W=gF`a7WwBz9Oh{oH{Qyg&;c9GN(@-69Yj6K>+~) z0qI5>kp@A!B&54LRiwKcq$M`pDbn3t(%s#&e4p=mXXbp4=DIvk)V=?C-)sG9p?UDp zA3qTwBESp~930isrAS5Q%N%yK@*w`-2H{FCd4}!re`Tfr=f~&V4fw(jsI>*z2B#Ef zr-v(f@y~XJt+e1^FA>9!T;hPdVZ#elW8D#!Uwn4JX`J)SFYIX-4X{A24 zIgWjyz{EO&hWfi2)&!-b--H;}M=b&KYHq!4ob09m899_g@ z8XNN-pO-b$DB<8yP7)Mpmj6A=|M}hjx6<+dPj%@3fBdjM0^57|3=|O*Prb3iWRhPD>od(-yF69qO#Z~5 z{E3Vd)39{H`mF~a`Xdu0-ptW}4xzfE3Aj<`W?Iyk1LP&3kB=~HF}@FQ6s!-4av%MJ zc!H^+4FNr0#9+sPo&;y`ZS?;>Sta(fCrF{CrGNkF@iZ;#_SV&*{Hj|!|9SHOFt_%s zm$%+0^Wowq$a8QqDJrQsp8Xj=!x^f3O?z|c#)j7e3ak90&8mJPiij%L!I8G;cL9P2 z&8-Cg<3QNfpOoPMWzIF1I_i^SWRJG_XOXZ~yt7#R+n6_M*LFaA<8MYic5v1Tit;X9 z;a=tENx=X|?)6`o%}$cSX3FmPk?NNBWX;6-5ZdV+NOTOSCibB4J#MO}hE8I%kg zu{OOSks`d?C5BUZM2aoRKiupS?=Ouz!SC>9J z`Rx{J=enPn)f-`|JAo)q{^_;Pn;3i9yx*)*%Db6`C9jyttQK>Pm3qG+NWr zk}s#Z-~GS$IN1y6sRz^d;EW{A2$06AFJy=u?;?SYpDYM(s%ESG_s>2rTwYCvm>?6k zk;zdv5Vu^F+Z`WU^E7o3!sUpxo3ZcSwR14A07Jxw+^&;=)MBH}(DYia>6`PF+4{#W z4*&hG*LMLAM!ucg)=I14Y+RC8HZk4U$wSUh__U`dySkdaBQFYgcpS^3vG{^r;ZkKe zd1-!{hLN6`Mi_LX9E>>K{RY;U7E#B%5Bb5$a^qdsEG9n|5ZgytoH4~92Xx|-Q;NX!{QnNJiY`3*H zGryD7rG5&2le1lO87-IACyZCh-o~JZmgkxroR(6S)}FWzFWA-X?*I(Iv;}E4E_mWq z<-RCm-~`~mc(%T_q-9{h45A14v7B1QCx09UV9Fl+NQrDYpPPHV?+d#g%6%F@TO&I%z5SM&9)_nb!WwOqDbdSsh4t;%lxIw+v^N}aV;o7GBuR?YxPSYLs8 zasaglpOk;Vu&lz1t$b*-;U1|=miMQr<308ZE_g89CGKEQm|ElnIRue}x61 zgcXlNz`4Cc5DFR#E6a;#p!Xc=A6F)1qA1R+F3w2>NMD)U+S;0hy$z{vVv31rtp0bh zM&a1&FLTd?$S5hdb9HUC^$T*-giS5o0W!Pwt>JdEcVl6+RJXOAt*k;MET~}zPtk4_ ztGry@sqUXZLE;MuD9^tc`&E;i=NaG7JgiD(bNB1IZ&6m32%yC%%Lj;d2VFfqvXM}%=UoevFpN+VFYoI$}ljPipk5_eY=Jw!=0iF3Tgo#1+=o%IdTX%c2 z-1_R&;Pm+5@XHs^mY235S2JB!qMU_QPA)t&U+uexht8*8UGJ%YFlI+c&=6#0QS5AQ z(sh*mJ{UL8?-oKxcavv2jNBd+LPmNgoR(*bua!z1DbIP|y^xnp@TBP5xE}Z3r`utV zd#SKlgMJ3n8GYkL$e&o-fXAVSJR)Pf#u-BO-E+^rudQVPp!rUI#Lz{`jZJI$hOmui5f(y(;0;nVSAQ=n+ z|K3#ZjuUbrwAg)rc~!*1^4)$0sUrooCc!N&DU}abtzU@u$iq)WMGZZR1g6`@c8V~w zqQc?seJ{nwKOAe-xEZA7)C>=g=`YNXNW)&@pbMmbYA5^7mkj#TY6ts=cW<*N(6cd* zPYiuhSJ66WNU-8=DaBqTQb(R`8$(o-;Oh$i=xzqXV^ zR80MS8k682-MM7Igj4BUk)4toWKGXeT_J*(01TEtzP=#q_iw!9k0Jy>SZU3!rKwqy zm0VX>rkr1YRr5v-c~K4+i^CyVz{=Nn1^_rRG2ZIhZa$j7y)X8yUDKnTNOhX)rFcsP zpOlQ;7wcFsd}T4k_A7gSoYFVId7-$P{$ByaEFNrm%sxZ(tY%_R>jG#b?ws*d&MXWE~*%;yq=Way{R;)NypT z0>y*@Jv`e?J!uc{X-F>m7{rZ=RLiBxANI{7T?cG?YgrFrl zV_5{}t5#ON5TTG0VvV`mpiS@A)jQy$KB+TsO?AzdXIOgea4( z|N8eZS1zh2fyMCN^4=+2^u_&<{Q=FJ-+xQGA|4N|?ACFKWUX=HCwY4WWBV9y0UT~A zm_%q7xtD`{MUwnrkKIaP3FxDwa>gAS7U z=6#(9f(qg7*CY#=6Te^aP(K?y_8(NK zK@zH2SZ*@gu&{UQXYtj2bY9WVkq}3sr5rBGT>?W{cSM1+${}VdMNSnY@tUE1;&5HKH z(fTtVL{EWoos>Wga8|(mV;f^IW+X(^E%v6?Qjt$^q_JGNWeiHrP>J8uvp6ozS8g&_ zLdD2&bF7z|4z=cek2chu$*|Bu%{jVt=UXI$dfa}^GuNAbJv62u^jjLmUZ((kD=TLa zwJeqc$6HeFH(VPFsyo57&mTYT6iTv(1ve_3lAcYgxqjBg4=yZy*t%797MPmffj%w2!w~X-oN&Ym!jVT1Ay!PTy;i>L{Y)+uhSoCXOU{}oI0NJ zY8EL1sKH6jFW3_tAE~7Lxxns3&+}{ETK%n6>vLE>>@V&g9$D8PEN}3qq^A$VPbwVj zL&W?fg>mp!os3pyGf7u!Jli;HT&ye)d>`k(6d+YJwgp?zuzx5X@1rL{UDFjFA04Tv z#M&zW5(~MbzH#JOy!2Qg1y(vxcDkJ{+zSJIEUTF$5d1i9{$dgqqDy+B~Cb*45d&GK@_-|bAdvrvmrzLS) zG?9NLdFpF7#U;SSnDCCIkvup;n>ro}WL3Lzd+gl&5(|H6 zc{^)#qkSv!eiL@l!onjOab0|_PmLs(~r4UY;xTo~r$kpDz`6!FiwqmvgO8((94 z_WdXP~*`1&ECvHoCffkQcB{4Rp(z3g4_mhCqLnM$XaUJ{#vgdRK?08(J_59-E9iAW9 z7T^&(iX(W1gH!Wme=X+=Yq8ZxuboEwe|#E#?FOQmg9&UF)*nsPwljq4Pgn1xT(yC~ zp4h2WK9j>`zHJ)ol-Jy$M$h%M$en*;dVKG?{+dnw&fs~C5V6)gj3ouE-!Pl91P2jS zE@`+ddh_)snd|Ol{q^372M1U1@UUzErKwuFHM`44(?qrW$&+DhPn0baY9P5554(2T z^iz?fqp5Bq`PXfz*P5nEv)P;$b8WFs=rd)zX$Xr7%G=BO3o>3DMJ3G)_wVlRKSYh7 zzP?Q4v>n@3VuBhy$oqJAzujrE&~sv)7nNj1oQ&>ikV*}Vnes?>yU1og*&|Iw!5%>E#;mBh9^G68>I<&y+k^0! z>7P)%iJ@1n_6*ZjM0tN)54T6P@YX9uBoK)4nh3+G`5T>|lVfl{5S@*^)6&)T@ zjH!g7bafyxC3 zJ?!$4UBP4Y_3=2Pqvm)g`@8>i?TWDbgvm>*! zvhDxkG8btME8l!2JZsx+*Ya{?=O}SZ80vQzo_I2H`@N{{abhpeeI)ML*xqtegIqV@ zsfCt^FHW54NeK$EeCMNR>?{uKx0jOYjz@WLxcwEQ%HM#z3D|G9W$ll0mGY@ahsPqF zpVzRT9u5U!&rF=L?pITh%eH9H`5xqBEvhFb#uwR{D<+ox8J^aqOB(g>%`9E zJR>5zd-pzu>cfYakB$m6ZJ`H&nKcRAu4!4xiF~)9&Wkbv9#MDKUB z8*d+&N+Gv9Gw@YjHu><{AxJ+!)PWI|4$^y&{QcQfUK;fSGf;V9v6ZF88@ssF!8K^^ zfPzYUM*w=z_2XB)9PHK4^lEZa-Fto_-}Ow>)dgo_$5NxfnF3gHVv>=iKM6+%sq?yg zlr#DGJS1gUABmS76GX6g-5Y9bmo$|u<`$cNctq$-g{Hw`S<sFS_$dy}Uq44j;!@qyRZ!G<4iSemT`t49Z}^I%vu93?BQ< zTMya`cwAbV-o$g->I-HaqCI$o8qqG~sqVHU3GLEY2$aZVWUREXT6IORB{`p>A~lhb zfKO^^KZI4?sd=~la3+xknt<4lgz!*_yTPG@3cL1~+dYBh*L$pudePGfTPXL5p(1|E zW>SYFJ+RM|{7F_`T6;*n;{m!}EMz-uuI?V8(WUivkJ{`H6*862sU|%%*mte zIL|tn5AIh10Z0EBc*p<=P_()m%w{wi{*gJ9CI~>VjZ~kKC{m;p8^69|Ax$_o@on3zy+X*u(^MkF;Ck#Klex6XwKRcdD8`_CsHYb{`Kuq$`#yozaDvUJ-UlWBPU1%gJ@oi7uYc+EcZNn0E9 zm8WfN-CU^aie;5t90Xlgnl8AnDUJJC$~&JdW%7qJYelN_YRI@uJKflSbegWcIo=53 ztYl_jw>`eRhrEA~JI;!&P)_D{l$)A52oeLdo!L|uE(Uf|ZhED3Y1iHDxQQ_Sfng~X znWK#rHD7OE5n)js)9*agA__uUA5_hS6*Vohw>v_Aq{(9W*`%kn5l%OV7B5q4P;B66 z`9>MS{#W8}z<&rPQNtY^u4g{V>5i-Y>W;G#9oDus#3^H^O@YTFuseUaNKm7oI9fjN7-}88dW1quI;jsNmGQ6=@A&MVD}`?|kPQ$kf?T-E_X*YrH5GiIFz2 z`)IS2pXks)OK2|Alf6@SKD2LU=p4$?)okSOUo8MT+uHr$XQ48Gh*Os=&z#Jzl2~LA zImM~TdB<6Li9wR0KHk2-_>j36vs_#w69oE*f#T|XwYI$Eo8GtIq%>~@Qv03v8+b|@ z5T+v7L9HsqUy7s3^OtH%?|U_>*19tKHD9j}o=}=jWxumK=ht&l?H<|>bft)M~C(-?B%OdPS-AsOkie}IJI`uUb%ng;^gG2 zsUdyN`)@CgFAnv#y(vKaomx{N7^BY0tJ&LFQGe#cg-xZDG1*vDU#}kL(e)Qb*{@LV zjz|*gZqq&=&6k_X#aTYI_z2l3m{7y z^M4`&PZhMvzTZ{Mkj^<-*%@#VNR=X(Di=!a|M5ehqM|Csc{Kh4i;b-sZ>C<)xQl=9 zs)#ab${+Qu!RZBPfq%mLOBJ^YbElM{9JNYa#?8=RXI6}Mi|mjuKXDN)l7Zs zPwQ)FVIV?iYx76d0pWeXD127em&EQrl!GD_R7CZ%&Qkh%lKd}~;4eTwA$};l@wbl4 zFoJ@G=G$A?SQ16}p{y8DT@c~Fw<3Y9_HJ@us_majOI}p@KKd)Rl3oq@jl;cE5A2@x zJj2nY#YG0YhWWs<5kHKN{5^?INjW)_b601?#EzZq!xVBRHaaFY>6HY@OEg$yq+qfZ zyLbCm5G^4Q2gjVhk`;{Wp{kGaephwyh{xj%rKNzTWT|rZ!rrK<^H-A$DsjgaYa)tj zOQrICd~}iOH+mBIsgsQRJjrSXk|s89yc$0Wi}u&8LI}y)*5LSzE?uwdcGp99RMxK1 z2F*fg#zP8jrN|KG#>v)`#lprbmoSyM+~y@qMdLEj^!QCOOssg~l!`RW>HT-&;VHj% zYsSlC3VGZz-}8<2f4B&LMIN98trB;_ruVv-CS7WwiY)<`3DkJmX2tmFkiLx z=2X;bCL{-U`Usz#4sKCOm=@Z37sksOvEfNv_iW+BzI*$laj9V3I6`@vjIm4i@4;CR zcjYiGVZos^3=(lo3BX712kFwc%bLrYt@~ODd|BGuR)3Nx*VgGCoCD>U$nNOvU2+oA z6L@^*%%K&PfX<%w;6vq1WC72p0DXiP^n<4JiRJqDY)1bcT^lI231EO8u z+S1Z>eoZeyRW%52EC-j1D5b=IjbBz;QG@Q#rmS3*(=N6v4d;gBQE$?l6zwZ}$!7=Y zisJ9fem4$MQW145-bBCV^J`qf=dskkNlY*~FJA0o^kI=|oS8}VzROZpZRebM@v(hr zf11ZxlK-K|+b-5-yk8p%Vo&6a4-c)A*erf{4`hBEb#c+wK0OU_ugWKn=x9XV_aVPN z)|+{_JmN67`PQA?tNY`VC~yW3v36<}j?Ua@Xj&@Ee7N$uah72<32B_en<>}p&D*-4 zCFQGvy(w9+PRYRDGTxkCm@I+IrCGwns!B;cw|81qZhQy(anCa;KI!c3Fu{4m<4bv} zBm**s;~{!?a@j8pm46=V85w0)U{(J#C@q`f3{J8;uTV?Z2@q`bSB)3J_e~482C?S& zOhy1cy`Yd#jG~k1Ig?e8Bua*Cu55i1Wn3dEQRNwVZe}^C(}msYy9mh?M<}`6jxqh3 zH4{tz6OVcw@%oN|FI1fYGF*^&=jh}#HN}7Z?S0FYF~GjMy()c<#g!EWghcEkr;M$w zEdX+dM~0+Rqk+{gwgDd-D@X><@L@DQv7+a+$%UgZdY;+_)ygyG*2iWPF>-V*{k9SU%m!^*o zc6xdHpJB$Pu*My4&o~rkee2fs65yxqRmH}Cd9|3I#njzDmAh@xX(j&O5A>oHLZ!ufm2un__+?$MlmT_%)d-H@=@}WZ zh5uh$JHSX5NTXUf(P8J|DPYKf@xbGFEoN|>YNDL1_a~N;r6XL1ifzjG=b4}MoK$2! zxM-LQ%Zgtf8Kv_#&6z_MMoVjJ-WsiTV&Cp=u*Lr1-`~Hx<32*20!Jz?dJ7%sqJ@pX zxee@}-96|Jj8W=762acYrI7aCWs_9x)|pHF6zXy_iELP?yCV|>lj29kDARoL@~ zSI#x#Ddo#@*!yzT#H)VBONbAX8RX)u74>~oa>v{DS#Yx^nCyJHI9;5t7&G*6-3T#= zLpsSqbkVWU;ey#`{oD8sY0{WElE@R??(?VGdvLmAYl6Tj9(h=QPe zOL00^osUBFeL6HxrWK9R4R{QqLXg+m3ET5$4NgxMI$n>zEgcnIT9jefk+|$U8#v3TTnNH#dKvhe%zyFu1d8 z$TaE}vT~gYi+|=jJ2FytJ5DaE_P;0I`kvJ;WG@1I8B`^9fN5>7McUgtqKA~{=Z_6` zYA}|H!iKcDx|+77uM=A9zOYOkR9)?dx;^c(AN>WLE@N7`Ibfs3jH+IW#c1ZX+m);F z``5|$M{|pFay*hu-;b9LL=fX%-f@Q_RUG*(YslCr&rd{YGhd}@C+gx#M9j+(EE?6k zIOJSe@{$#{xNch;yOZ6+{R6a)j*$!Y=%0Vu;O4TlbT7B;6-s>zKtu(pTWMV(h?Pv| z)#NQwjiq`-)z#ftyi%WxurRZ{NFrmFixBnr-nrm#aZXRR9)5;QH=FBo^_I3iGBIMy zY{d^wzjm)mme4( zIzFJEjtCcx*n8gKA6e&mYni(yy)vs7(LC8o%gKg+0R{HLvLH=u};ALx;* z%R6mDTrS4e*3#}G0D`de5B5lqA0Hkb?n4#3w|B%i^NxIM)v;f_Piw9ODnEs+VJOIm z3WXF_5O4Saklic4WAGVubaIr|O4(M=Y4YCHyQfx7n9Gf0U8jufoS`8)_D)3@k9^uB zZ}fZPx$K-j?+kL*P?bvjpUUVZ;a4UB7u_NZ$MjlLQzB#;nJqR-O9-I8&fCKJj`s$e zHcdwxyhQZ3()tSMpb!VSlmUk~U3ARsYV;_tVbxQg$3y>J=!kC1a}6D^f=h6+Z@vg>Mk+O^6?Ub}|CM%;V zGZt11Dbe$ivXRL13Bw3wcnF_i;yHQ=7zEoeBrXvOrkzTo*|KpDEGWAPGxct>#hH-X8tqT0wuW>Yn4W ziC9B-Y=!*lSvXm5;SZ#(c*%X-MlG9TKS-bx)cpZd7i$ObL&mb{tdhE#92l71kwzYJ@(@2>`ImhEdJcXJ|Obz#E!_@&`2ol+iRpBN7I3w=cJ zP|MR+=fj0mRiW#fVo%dP561cX_^$ZOZ@$#d&z&<37S6`;B6P}?x~Y}jKaNo&?+B~l zJNb^YMkwoC=64}R79UK}hM|Wb5Y$nf!=CKW9tCVnNd!nISI9bBEN`BPWW9tmjZ6*+ z9-iaKVvY0!o3rS|{gn3yc#n)4P$NMlIlyE=MB%2I%v zQm3V4@`M3{jOTzTt`Yr_$Ao@fyWWccLF%w0-zI$2jQQ1(g?)P%!OlNqb{)rTPZ-ap z$8D8Z&=pU?iO)mLNXhnQnw2nEgbm!m;3HDwmgk~4Jx4x2M^+yDI-XRp>s_$>APkpo z!@lb+r06oluW_$Ydl^)bO4Cbx+;K&FykBMZR*Ycdn0_EDbQ2Ct;PY4LPQVL9n+J4Q$w^cglso5r`tO0xL0w~$xaH~g#?&o9YLsi9(HZfxyM z>gwu{i&U?dvSnuBwm7P~$gH{3QdRw?ivT!?_0>gAtDZ{_vB)Qf?I@(kaugXfkv?W& zcGdn7+YDRK(LGteRaI4msJ&?r*@{z6r+8aMcT(5fp0(B*gm-v!fbGN8kr#=hxAXAy z_Con2UFNUnBKP?h=jLL#v?M;L22|SYE#q+)D5#Y8jkJu=64IF{ACKr=FC?(4^*<5b z96xhW(97J$l^I|_c_b03T3JG5=OQa!gGiWOZF|5drowQhq#P#X?tS{5AYW;@AUsMn zCzmc{koR0>n7HwSy4!VO!+j$b(~+&*mUp)H^$i_+&`OUVVCmmX%+g+*)|QW&U3);f zfXBn`$mNWDo*Vt)*nn@ZlVv)OiBl+}{5U3*L8F%h?o7j$1r@i8ex6y)b@`>d*>EWM;M~-Hoc8bg_?`^29M!tXEZDMuV z_U*V#ez}+BHZG(_cjazox*kk9nbprsoocb%NuoX7&XKelH52XZT8}u!8${cHOKak? zEg&S6nU~iS)`|*{t!VWd)r17bl^&J&;*MC=rN`n^o@02ZL9K6yBBTZQA$t{#r!b;( ziDhII3tMe<-Ee0+^w8Rl>$EKlwl#%S6;^JQHED~6`S|A$kLF}+Dw88C(r$ngusrap ziNgA!#~%PutRb=qOn;P?qm0enRG+5RoGkQb@uww>t4LH6(ng+!2&RtLE^w5_sPqQM z;KoPtC685Z#Q|!tlB+mPw!z$13vqg24bXnbKoj+WA16SWmBcpd*KfkU?YT9B*L6Bd z{T^0~dcBeoVtNvPnigf#`7D~rgWXsQ*y72`uUXzP0ld5_z1JL>(UNE?qNi7_xCwPM ztsyHUr;rjc$h-{^AshHLZ0)opAdg~l%JJ6 zA|OC=@!-s|l9Qe-!upY{VbYYi>-(^0xJjqKi6t$^HYe7z{Z@K}tExys17{KwTV0P- z7LW#(=KqK_JEkW#<0s~fT-(>uWj-10Qlr-kv`xN)UOHpU?r_KVQs87T#1Wmb0_Vrt{V5@ zk4xzD=w08Akj^sk=oS{~J$(Ft({=G@Wke^+#)5bxDBp;rV@1thzQiXbN<8y?gcESy zDaq~a?R$K5U}tR`5)^dOp7zAXrc)mA#Lv4Xtaf0c+$j^ra7c?fZnq%czkhDC;0Lfa znI5(o!R*AksJorRnLS4TZr@MS`KVk4!-8}#DIGE+Ozik1MmH&GJ`sZ01Quze;b zQ3i#kreb7GylDOc3`~sw!S!^%&;nyQ~~3B)YBDzruS3X#sN5vb_9I#_5O;QufQ( zE?EN8Z>DY^)4A{uj6r0Pq`c{r_Y`UouW0lKBj%REAlXJ-xw*xNKU?Xr+zfYJ%%C1c zM2B15ncehv1#yb6x15}iiEs*{IZ|}=$UawCJ4i~N0PaR*Jn~5)6M^98m$m=mY;3*l z;#XXx2Ux1>*s+|$cqwE|P)l;wYP2)NWJTU%M_6^;RA;6q5GUK-iCl=#kZw~xCvlGFG&=#`77r)TcVB!u`TF5Zg@iz{Vk zO-pTAuc`mZvqrs&;uMC?$PJ@t*$MI z@z>T$Pa}nvWVZeljW;Grg{3wyzh!>MR3l01 z1oy+*Y~%iw?)mxo+Hthm*KS?ECe5mZ*Q0~P7PdA=`+NP>_kFzE1}CGuq3*Dr6gR}! zv3_`$MVu(mLx|Am*RY|IS$^(f*+gjhW-$C3A*1n)FU+HJ2>(et|e(^&knxk#EFPQlRRZA;1RY6Q_ zfHAYRg)Cy0+|M`A$OL*Nm!P14fS@4w_HClV2AP+B&1x0aY+jAr4x0t3(+s;N9g77+m8 ziVJKWM{%xuD+;rsgOdKj^yfR0$U?24z-1V8@@%*aYY_TZ%5D|O839~GuHcU$1~G#uEPg%# zumps>_jy*wTcCZGeeD`!(fII=c>LO7yH@0aIEH4%`>Q)B)%yjC#u=Hyc2RSfp)>)4 zs&WKX>oL{+Az%KkYbX?_b5W-9J@DHG;q7qeBYg z9x;*07otuq8YNvlvZ?wDWTV)P)zIU^V5v2-v#}TGASqulxd37iF?srR`@!KvB>W_Oz%)|WJpVvZYpI%lz|ywlkjF-PzedO1S zkAoMk$jYGjNmVKDs=rE+iUmW4^?@~g0|M5iUY_$z>8yAzv-gn_F0!PE;-br{_vEa< z^=tox(>Jqx_(L46Y*iJxl6P^CW7Zwb)w@rIIbHRe5pvoqI1^1H5rU~-@LvV&tkqp# zA7InKsj#uITfCP76E?O2D^XQ$l0wtUL8kmsl*6t!;N#ge8=8*qZAwaUm@Y=mvwdN&y84abfrIf;=`eW3MtOd}Gcs)1bZ~P$LM-Ksew-Wq543yA_WCQ6 zjS=hBpO0i{?c>ADc8yp3)>)@1+w-E_>ILug(sLCYC+7JK5Zp1jWmOEE6uQgtXRxpz zN*C_20PU%o@M>GrV*C7Kl?@-5%fbc+95~hF($x&A&mKpu%l`&G0hh%Lux!Y9Ix6*a z;VAK?iHEsopy#hb_*8y2-9GPzUO6u#)}X**ds8Grnak?9=CnzBOBYtYxq+n~8X6O7 z>Mp|$D?Q0)Qp(HL({E)tlCOLriey!~AMw!pv7W@U{#=L0HWwt-6;;&AW#7F;eGfC9 zEqAG`uC7`W^7QTx7^6mUe2Et!EO6MJBg1z-^|4MBY^}-*$24Gyt!PRE?o7NFg-Ek_ z+%F2Td%Pz{fvF%WMpZM71I1KVqCW0BNsyRd&M%xyDyy8{ZXlL49v&g5tTA`h)*c(2 z)Pu&X^ffY;AG6WS_lh6d5y~#dY3bp991Y=rR6?p}V7A<6%J9{(yVL9ja8hf&!-;A$ z3tFjf1TZA6X;f-Wt*sCHt}i)eRk)Lq;^6@X$VbNB37~2#nGc_YSAjCmlFROV;~_H{ z05|Xa{ANsLQbND}%KFl36TcvMp zPfY}%-Szx&e01!3b=JCk-e>-9$_w9R;3J8tf$2o)g31O@yoju5ch^9IsaD}wyFm>9 z(9Db||D&^a=sujB*5!ML`)akO7{!IhU*ElBhu~dUH_u~z8iR?@ESCMpp>SdC$WyLw z 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 VPNЕдиная семья значковЩит / 16 ptКонтур 1,75 · сетка 24Состояния VPNОтключёнПодключениеОжидаем входПодключёнПереподключениеПроблема сетиОшибкаНужна настройкаСтатус неизвестенВремя сессииНачало25% прошло50% прошло75% прошлоОстался часОсталось 15 минСрок истёкСрок неизвестенФорматы времениЩит с прогрессомЩит-часы2:182:18Щит + времяКольцоДействия менюПодключитьОтключитьОтменитьИмпорт ключаЛогин и парольКопировать IPЛогиОбновить статусВыходИсточники и режимыВручнуюАвтоматическиКлюч на MacBitwardenУвеличенный вид + 16 pt. Цвет дополнен формой и подписью.Пример сессии: 8 ч. Контур и внутренняя заливка растут к её концу. Набор пока не установлен. \ No newline at end of file diff --git a/artifacts/icon-family-v1/icon-sheet-light.png b/artifacts/icon-family-v1/icon-sheet-light.png new file mode 100644 index 0000000000000000000000000000000000000000..faf54aa955a2e51d02b7a7e00929de8011e94349 GIT binary patch literal 267643 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®Y(rzq{|3t6aH{^ivfE_XbUoN)s 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 literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/icon-sheet-light.svg b/artifacts/icon-family-v1/icon-sheet-light.svg new file mode 100644 index 0000000..e054d5d --- /dev/null +++ b/artifacts/icon-family-v1/icon-sheet-light.svg @@ -0,0 +1 @@ +Lemana VPNЕдиная семья значковЩит / 16 ptКонтур 1,75 · сетка 24Состояния VPNОтключёнПодключениеОжидаем входПодключёнПереподключениеПроблема сетиОшибкаНужна настройкаСтатус неизвестенВремя сессииНачало25% прошло50% прошло75% прошлоОстался часОсталось 15 минСрок истёкСрок неизвестенФорматы времениЩит с прогрессомЩит-часы2:182:18Щит + времяКольцоДействия менюПодключитьОтключитьОтменитьИмпорт ключаЛогин и парольКопировать IPЛогиОбновить статусВыходИсточники и режимыВручнуюАвтоматическиКлюч на MacBitwardenУвеличенный вид + 16 pt. Цвет дополнен формой и подписью.Пример сессии: 8 ч. Контур и внутренняя заливка растут к её концу. Набор пока не установлен. \ No newline at end of file diff --git a/artifacts/icon-family-v1/lemana-vpn-icons-v1.zip b/artifacts/icon-family-v1/lemana-vpn-icons-v1.zip new file mode 100644 index 0000000000000000000000000000000000000000..83c380c906898030fef0bb7d0f7ad0cca8eb397c GIT binary patch literal 29676 zcmZ^rWmpwj^Y$gBgiV7W-Cfes-E6wMyFo-?)7>GBNVhadm(oZI($d{6@5ZB^1JD2c zurDt7#&7PKHFM8eTR|EM8so{6CvZy(YdWwlaZgyTmDQ z{{4uk=hI6u6??7c$tbK*28&fc$J;I^rZaMmT66$tLZ3V6oOFa8rKlyJ`Da;`bFMi- zle^^HY{+W{Ch$0Y5FpO%jCf^b#HndUF0{{cPQt}k5_ak+jCwXyzo$ol7?*izai)I5 zoKyOJUo$eDXXXl-Fs-&#o2k4xhNR_L(gp6qirNhhLuW!vOqJ_8<~V*an$)yhCQ+eO zlF&O|w02wmP&T%<;q0Qa9_k^0>+ckNN8o>47A%3s0PJjSO^lrX)qnzzTo)6@ zr@pZqirQoBP||iw)WKTn4b`UkF8v)U=Iv4obAZ|+8U`HM(Bk)Ce>%97cOI-c)Vibl zR-E6d=bWrdY=+?+hF};FWYprKfl@uNpg65rdn6-&vCoZ_RrAtI30zmA zl1tq!^WPSGpA&W-A8afH1}zm5IjL4#&9)`3&;-F1;j7ZU3dL}&H{?VYm`U)&R8;X+n?3?xOT{^C8Wp{<$ zqJ91#QH4tx4{4Vtp$EaY7Gkt!jAeGhC0TIoGk_c#3WA)^!o`dp(|;6zj>;lDf^x>D%qg-VV1^_T5~VEX9v~ zL}FZG{Srds27U)4!Ud}e=P@dKkAEcVV$$Ui}P=Zy0WFF5%U zvIUZvxt)>ITcqd-XmieUZz8U21LYb1e(5&(7GOqN$S_=kj%DGczoOKaX@TH8WK9xU z)M}OpyW5*UOMfArbsR^;6K7(#^Ht!ik)(HVv!=zCQG0`*pnO?Rd((tMVYlqLSb7a@t%9*L&p_5fcUCY{^eJ-+poGT&S2 zd~sh*t7|KvG$(LQB0V!u#E9t@SX8#r@|{Kyq*WQ4iFT7}#H+%l0>Moq@OmoiP)4(B zlHly>XXFZC(?zUYV6{&=n_jR!T{^np?Y3|`G zi!g70)9h#RLSFeLQ|mgJ_0d}+tpXStR(($2P+`eSF2_ZCan=GBb;by>WC&S%q<98c zlk9TVw7@RE4r0HjR7(3~(hcWp37Hr02?QS5hW*4OqI>*R7cdX$z5YlbxeTU8119*W z@v*S6w{!f@p%>kJpN;`~t6MDSvlgB5CgPBV!Py#3Y7rsNz=d4NO@z*RfESjP$Q@=q zVvEM7&$VSAe{SjM?O5B{{IqV?QA;}Nedj~=yYoT3?|h)wlzw$S$sC%2(sh^;zCwHf z%}t{{aMeRn{_}2oatORB*vDbCp%tz@E>C%pBfW>JcB(I&#Izc8Yan^f^|!sRCM~YF zrSHpAc=;jg+urge2Y1i~0e@i95?6}@%j72=515*^q9^RWCUQ$D>76XAp{vnIv{~Fx zJ^C@6?VxlrA>h$1V&990WK4`u*q45jdDIX5Ci5Rn{Rhq6hirvz+~{bWlp0TPyZn5$}5SVWGE#o{9U=*j1szr_puIuxLL(7spxE%N54H(<7X>EuE|h}! z_>zI&URfGJYnYK695j0-f*9C~2M1qJ;-@*>YUsiy@vpCJSe~wj*B({uL!a(Vu-~1; zjh#)YJ;4REUO_r{@O|kj8EzB#bUaR~QcGUPw^1NX zCf-|#552M|EwjAkQTd7Vn4XyU4dc;q_6x?pB8j?hgusIX%hh;S<%^Ga82JK1GoWg% zky3UFW-yI`*ZUpJ<^})I5IkQS+>ma?m!}^Zo{R`>1YBA57=}y6hY)H~d}T8^1_5Nz zxkX7xooA|b)Gv*lKOLHhQUimL!aSKKX&mP*I&fg`K49tuN5mf`+Mi6Kcpq`s-|!8` z4NjC-^=z(WtFc{RPu+|~fe$jhgmⓈ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 Dnx+U% literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/manifest.json b/artifacts/icon-family-v1/manifest.json new file mode 100644 index 0000000..0a704a2 --- /dev/null +++ b/artifacts/icon-family-v1/manifest.json @@ -0,0 +1,308 @@ +[ + { + "key": "vpn-off", + "label": "Отключён", + "section": "Состояния VPN", + "kind": "shield", + "mark": "off", + "tone": "ink", + "progress": null + }, + { + "key": "vpn-connecting", + "label": "Подключение", + "section": "Состояния VPN", + "kind": "shield", + "mark": "connecting", + "tone": "ink", + "progress": null + }, + { + "key": "vpn-unlock", + "label": "Ожидаем вход", + "section": "Состояния VPN", + "kind": "shield", + "mark": "unlock", + "tone": "ink", + "progress": null + }, + { + "key": "vpn-connected", + "label": "Подключён", + "section": "Состояния VPN", + "kind": "shield", + "mark": "check", + "tone": "green", + "progress": null + }, + { + "key": "vpn-reconnect", + "label": "Переподключение", + "section": "Состояния VPN", + "kind": "shield", + "mark": "reconnect", + "tone": "ink", + "progress": null + }, + { + "key": "vpn-network", + "label": "Проблема сети", + "section": "Состояния VPN", + "kind": "shield", + "mark": "network", + "tone": "amber", + "progress": null + }, + { + "key": "vpn-error", + "label": "Ошибка", + "section": "Состояния VPN", + "kind": "shield", + "mark": "error", + "tone": "red", + "progress": null + }, + { + "key": "vpn-setup", + "label": "Нужна настройка", + "section": "Состояния VPN", + "kind": "shield", + "mark": "setup", + "tone": "amber", + "progress": null + }, + { + "key": "vpn-unknown", + "label": "Статус неизвестен", + "section": "Состояния VPN", + "kind": "shield", + "mark": "unknown", + "tone": "ink", + "progress": null + }, + { + "key": "time-start", + "label": "Начало", + "section": "Время сессии", + "kind": "progress", + "mark": "", + "tone": "green", + "progress": 0 + }, + { + "key": "time-quarter", + "label": "25% прошло", + "section": "Время сессии", + "kind": "progress", + "mark": "", + "tone": "green", + "progress": 0.25 + }, + { + "key": "time-half", + "label": "50% прошло", + "section": "Время сессии", + "kind": "progress", + "mark": "", + "tone": "green", + "progress": 0.5 + }, + { + "key": "time-three-quarter", + "label": "75% прошло", + "section": "Время сессии", + "kind": "progress", + "mark": "", + "tone": "green", + "progress": 0.75 + }, + { + "key": "time-hour", + "label": "Остался час", + "section": "Время сессии", + "kind": "progress", + "mark": "", + "tone": "amber", + "progress": 0.875 + }, + { + "key": "time-quarter-hour", + "label": "Осталось 15 мин", + "section": "Время сессии", + "kind": "progress", + "mark": "", + "tone": "red", + "progress": 0.96875 + }, + { + "key": "time-expired", + "label": "Срок истёк", + "section": "Время сессии", + "kind": "progress", + "mark": "expired", + "tone": "red", + "progress": 1 + }, + { + "key": "time-unknown", + "label": "Срок неизвестен", + "section": "Время сессии", + "kind": "shield", + "mark": "no-time", + "tone": "ink", + "progress": null + }, + { + "key": "format-shield", + "label": "Щит с прогрессом", + "section": "Форматы времени", + "kind": "progress", + "mark": "", + "tone": "green", + "progress": 0.58 + }, + { + "key": "format-clock", + "label": "Щит-часы", + "section": "Форматы времени", + "kind": "shield", + "mark": "clock", + "tone": "green", + "progress": null + }, + { + "key": "format-time", + "label": "Щит + время", + "section": "Форматы времени", + "kind": "digital", + "mark": "check", + "tone": "green", + "progress": null + }, + { + "key": "format-ring", + "label": "Кольцо", + "section": "Форматы времени", + "kind": "ring", + "mark": "", + "tone": "green", + "progress": 0.58 + }, + { + "key": "action-connect", + "label": "Подключить", + "section": "Действия меню", + "kind": "action", + "mark": "connect", + "tone": "ink", + "progress": null + }, + { + "key": "action-disconnect", + "label": "Отключить", + "section": "Действия меню", + "kind": "action", + "mark": "disconnect", + "tone": "ink", + "progress": null + }, + { + "key": "action-cancel", + "label": "Отменить", + "section": "Действия меню", + "kind": "action", + "mark": "cancel", + "tone": "ink", + "progress": null + }, + { + "key": "action-import", + "label": "Импорт ключа", + "section": "Действия меню", + "kind": "action", + "mark": "import", + "tone": "ink", + "progress": null + }, + { + "key": "action-password", + "label": "Логин и пароль", + "section": "Действия меню", + "kind": "action", + "mark": "password", + "tone": "ink", + "progress": null + }, + { + "key": "action-copy", + "label": "Копировать IP", + "section": "Действия меню", + "kind": "action", + "mark": "copy", + "tone": "ink", + "progress": null + }, + { + "key": "action-logs", + "label": "Логи", + "section": "Действия меню", + "kind": "action", + "mark": "logs", + "tone": "ink", + "progress": null + }, + { + "key": "action-refresh", + "label": "Обновить статус", + "section": "Действия меню", + "kind": "action", + "mark": "refresh", + "tone": "ink", + "progress": null + }, + { + "key": "action-quit", + "label": "Выход", + "section": "Действия меню", + "kind": "action", + "mark": "quit", + "tone": "ink", + "progress": null + }, + { + "key": "source-manual", + "label": "Вручную", + "section": "Источники и режимы", + "kind": "action", + "mark": "manual", + "tone": "ink", + "progress": null + }, + { + "key": "source-auto", + "label": "Автоматически", + "section": "Источники и режимы", + "kind": "action", + "mark": "auto", + "tone": "ink", + "progress": null + }, + { + "key": "source-local", + "label": "Ключ на Mac", + "section": "Источники и режимы", + "kind": "action", + "mark": "local", + "tone": "ink", + "progress": null + }, + { + "key": "source-vault", + "label": "Bitwarden", + "section": "Источники и режимы", + "kind": "action", + "mark": "vault", + "tone": "ink", + "progress": null + } +] diff --git a/artifacts/icon-family-v1/png/action-cancel-dark.png b/artifacts/icon-family-v1/png/action-cancel-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..d3a0ee1c840614a3545f9d77d9f7a9ce5a115e93 GIT binary patch literal 923 zcmV;M17!S(P)^*w{A%qY@2qA*T{9F*!UurO;<*JSxPVGXB~*lOMsNW)zV!{j zZ0SK{5^9D&E1p|Wf(zK|Y@Iphk17u&kx>7Y@A?+sgiKCB-N)M>z4QIb104pJqv^3l z4|N!hC;d9%JK%V?v-QQI2eaP+05BX+UODehYc%n?+iAbG?By=Q@ucs(dtY^&1CG0$ z_B*RSOa%a(5?I17YS_ahfhqi=P8=8{u!UdLibqNbjNupc;*vrFYxqUY_{5aJ9DY$Z z4KXCJhhNlAhoyuZ!Y}Hl#X>?Z;TJumC!~a&!Y}&ZAcTb6!Uu>10P9J}F?@hb0MJZA zuHgfO0)W*d%$@(4Yxn@E03h%ZA@MK(tpK3@J7F2Duly2f0l<0^*uw`h5CAljkVE)D zCIWyJKNE=0`FDvw7t|2n^7FdKI)_J=y@Vu-cR=0m`HQ4j=x+kOfF|LWJqx=wFWnwLd3A|<8KSrLACKuL*;|Z#MCwSn^Jdj|aWQDB?dKP!f$K5Yz5rXhb>TcGN|9(LwMBxL#?oRsz z9#tERJdpi@$igqFDIqv<_X{EozobG!KKliEj~@P%Fmvz+%;A^(?$Q0#zxU`_>=&eM xEB`_6{R<(45JCtcgb+dqA%qY@2qA<>&o5IZVO=XTm~H?7002ovPDHLkV1g`4q*VX_ literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/action-cancel-light.png b/artifacts/icon-family-v1/png/action-cancel-light.png new file mode 100644 index 0000000000000000000000000000000000000000..05b352af7f89db9471c97cfa34afb544bd01add4 GIT binary patch literal 995 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGoY)RhkE)4%caKYZ?lNlJ8XL!0e zhE&XXJLkM#u%k%(e$6A|7xY$m7Ah~$PQJ^;tt3$^Brc?~;Uc?%;E@-{)EysRnk0~X z>4BGb%+%J>z=#YFADz8=FGLLv?9F|CUb1MP>fAe)e`~j2E_$Bg5Gdk`iFU4#2p8X1 znEk3Mz2i4SEAzd&zcGKGW$B6kSarX%;p3?<&K_~hhws{NZCv^`>g&|*pE<^XGi#&+KS|Az1K{;%Fl`Sb=lk9EZQ3uyVZ8NubNh{H|Lr;pMrK59Pqt8zoqGH zH)9FcNoGGzd4 z{W#lZ3J4w3y4>BSVtgg<$N8A64}BO;OjS^=DbQhf;yFRYu0nvJNX3I&-iEW`gOExa zzZ|QB1!vG<_VY{!_OqOP=*+(xHw|#KzV33G$>Ur3#z<6PQOT=OJ_E^DYgR=Bb8$HiNU9*@xW4Y|%_dwx=Ob6bH zEqs#35a@lOFzW2Fv~#|5i(lURc|P}Qs`N&t1?}%!j3?}RBjdh>;YGX?&qHSxrUwB| z8%=icpLr%(zvJ2I*s{LId-YeuTg~u$cd&EklMN!PT|RQ2_-*}PzR~R0Z^u0i^A7uW zx-?}l*0#?VYGm2Sv}sJG>L0V%OA{bw_x0B7r}iu*HB{- z%a`9F#%Y{MEIhwFEWECdbes*4UvY>MV)F4uqZZkxdw5$~sa!-}6zek-+Sp7@vhN0M%_7Rz4~ z{9Wm&Iq4AlitDRZvrRK@i|zT`w4`A!lNd6vBqN(@>8o8Ah&Y$x1@3xl}u@lSb|ma-BwM z(~iqxO68K3%Og&m6uGsM&gwbOdCp(wInVofFVFjY|9ao&`KEigIY76mZUX=SigUzx ziF?40l$H|L8OAwtagz#kcEAANf5fe>>Kp(7x8g81`1qR(OxFm!_b%#WbjZtWuZgfG zCacw{9*fY`^-)lGns%~uhfoiZ((yDcU4Mzh?MdZbl_4T}cG=lth!`@l6}4ScGfzWL z#&iabEjU|L_^Emdr-%X}df@xsOw#*VNU+6Yvi4fJs3SUjUt!5XbOPgw@bE*y zS`#n5Ql;0axxRAWkHo+5S+fm$Oql=)RfH)eV|-Rz_{aB)>CeJOc;FL=_(jd` zbCFQ10E#Joqe%`H8*IptxGIwA#My6-sb_oneOv%NQ5%yoe|!CUVnoYsA8>1X`*rU8 zTBDidiN0Bxj}H3D6+xfU6k4B+|T2(Z%%HTWEH-uVk@oxZO1Ab$x%q2-T2O z1ZRf0Ms~H61l+A_^%1zJrg3FB0(4nRtH1V6EI#SrT9l@szbVD+i!swNj@O~8CS%M+1Dnk9uxP^Ka^XhbpSpJy#J95>?=EubGh$p= zbbv%<1TH4iN>ujWT>b_5*|jfalspVfsw`)h7{w`NyR}q_UqMaJtfNylwRwslGgfuB zwV`gbF~;iaF8+m~ZKAh_bO0Vj`k_4UL1rEb+R9>4i?M7%gTP_%(axwKNReH>a>yK^ zbV_tBe|D47wm&te*C!)>N4*OTJ2Zz7jz{V*4EC3xbey^XgykDjWAriM z$FruNlOCZ1EbK(fYTPjtaHp(KD`p4cqQ)T9C!e8gdrZh^Yi7Uo)4x_uMtxTVX vh#jvX5q4G||2&aH=D(Q_Rs7p9J(c*E{8{UA!KY#FVn+vXST{_AZ9vLj%pAX8 literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/action-connect-light.png b/artifacts/icon-family-v1/png/action-connect-light.png new file mode 100644 index 0000000000000000000000000000000000000000..69dd6eccafa5b2969da20555d22b733abdf019af GIT binary patch literal 1570 zcma)+XHb&~5Qe`9Bs7&GO-aBOq-i23Ef@mf0t67HnLq&P8j2DrawkS^eoCv{A z2SKWYU;rTyF&~JOqXtw0YOq911d&63-jAD`eRkiOo!NQ+>~4meD`BJjR(SvbHaa@s zkFIOL&ykTyUT?)if(NpXo-`vS9coihio#24{`Nod zAsCei$TT}$(McrPS`d6gj2<{dp&6jp%6Ub#>JZu&Uqg7LbAc~_OyvPq+R@s zEAqhV@-2F;h6H7)@QE36y#Wp&g<;C8)+amh$|HA^PY<1ay8|E;SNFmL*FEE6u~$d*7s; zDLu`~nn+bTmOTaplo9idId4b)tgvT~_Fuq44$WKA6MT%+4GXOFBF3u&yAL*5Dywu7 zW?xx8YKXK))jYd5k=`I4cXubb zwZTj;4^Q@6E{o66C$UQZ>EQYf@9@Ki;*glJ)M2+QUvXFrPprBoNnk z3tEEovrPKl{4TChzGG&pzrjRjUqa^2;>pf**ziK30^i*()WEI)QutLHUyr5?N{FM2 zq&rlEq0U=Ul(B0U8q5LNqo$s$N-E;9Bua>PaXa2)Gi((5Puht1DB;!9Ra%Bjz4;{mMD8D4D-Y@(Ol{& z)2$T+k29?@7;W#Tvc|vK9vTdY(6+!dm#{xMp+pV2k+pg_p4pAHnCqY-U74PiA;Fj+ z>#z@DL0YQzk5;~QeJ#?HOXvno&a2b>Cr-vUTCfrHde(ya2C1M368J6lImj7})YnT_ zNe@$c1d%LfgQ+*-tlIU*U*>Gq{6pro%87T2L9=k+=DAB4A-(C!rrq@sXpQ9I!yTzH z+t1E<(A;0~^iz(0(2c0v|?!DKV<<>*DF}GZrUwuB10SWUZ`qunH!7~7B{}V7xp?~}sTlpg k&Jzq}FY5ln&1enMahNZA>Oo}a`qKv-?OpNJwgDIa0TN5pH2?qr literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/action-copy-dark.png b/artifacts/icon-family-v1/png/action-copy-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..815fe2d38f6abf878ae0b25d80ef8631ab8ef35c GIT binary patch literal 692 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGoY)RhkE)4%caKYZ?lNlJ8GCf@! zLn`LHy=#~!xA@QN#E-AN9FH>Hn7&}0 za)Tt}8IA-u24kiff(LYNe{Wbf@4Ww1)dMvfcky&xUU6ZDewltJ*D8_yXT(?QJpUZ5 zs_(e@Y1NfY^1&)A#haD^*-zwDEFG?&f4D6pGYca+wnH#5*HrMNL zGG^`BF#RYnAdCK-Ue;H29@0%tpS-WcXLxuD4b2ti?1XV|FV3{d+fPfug-@Z3! z^~g_KecrV{P(5Q!#@q)BF3m2D@z|wN)$>bIs#o;{(1eqWMKRKkFSXp9%)I4?oI&Ke z*Pc^l7A*bVaI!4ce^rioQT3+M!o%+vKgR_8xw&L*HzP1bl$@78m$>NUmLS26pakOS L>gTe~DWM4fDbF$L literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/action-copy-light.png b/artifacts/icon-family-v1/png/action-copy-light.png new file mode 100644 index 0000000000000000000000000000000000000000..ceedb84e9f09e79475dd085f5cbcf594bd593479 GIT binary patch literal 703 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGoY)RhkE)4%caKYZ?lNlJ8N<3X0 zLn`LHy}L2*a)3nJ!}k`F5|R-KNh_UZD7CKDh}2R%IJM;DsaxC$3%%E~s4UUzOjz8+ z8D(gAFhJ3b?RuJr(n61;Vg3B`d+(?Bmi*DqFP>txQJE2F7X!lr{if=MwI5Tqh4Xv~ zxupADN3Xmq zoxzxChTwr7hBOuf<%Y=Q|LkAB*3_+WW9nJ<`S2p==byV9H1<5V;dIeN{qv;Gsf*Xppl8i(MIkaxlsK57Q<1UVXhx*?)oiOh|x>kPof&cGj zRYyJviZCgh>MOqg`v3E9@0@me?LB8&Z_Fc?hFL*(PdDj;Tm|wTZhJOwna?ir^k0Tm z^}H_BUuzcH=7_RQm{Hx91IZ9P`e>lFj`}Q|!gWdbKzPxr6lq!Bb YH_y1RU_zF+X$^?$>FVdQ&MBb@0I>u+UH||9 literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/action-disconnect-dark.png b/artifacts/icon-family-v1/png/action-disconnect-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..29272b22d1b149fc421aba75c30a8e9361250980 GIT binary patch literal 1808 zcmZ8ic{JOJ7XC$$*r}!VWoS~WL&-?d*p<*mH1;l*Dqf2+Rb#6}OB-pGT3e#%Xgwv0 z8MT&FBrV4piYh`PiqzN%t$OKsbIv>S&OLWM-#zF4ald=hu^1;QaaC~u0Hn~)4(9|u z;DmiYa%2${YhTgpRDtFrgEXdi2&z%GpF<8_p5Q z;;Vtqz4TO6h+sa<8QXflb2jHz*}9nDr$$-8fVp;#;wYm#>Zze5I}RF}R- zn~fshAIy(>ja4C0J4Ar1tJD2@mmvd3_T#ISjm_MX30+#CP4YLKXJ`KwcTW+Ub@d;V}GvPn|V=sARoaqVo2a5fuA<7(-#lR04Vt7(1!0pc1Rm5Hl?dyX`h}N zN#J;pLHW_5J`9xrl~BT!eANLZYzm-;)R#6If&3oZa~?Nlsm3a+WEBdj<(za=x?R zmce_%2;Em#^FQyZjHJTbYt$6X+%TB!qEQ6B?3}*z(q2NekpGiW1RkPZ@*PSIFAihX z`OQUh3hxr1&TxPw)a{VaP_~u;A87;2F^A1e2^uozVFt)2qY(wPw4Od78E1qEi=&BZ zA}MO`j}k|oiq2}f<28<9_6?xRUdjUnksD=5ki(J&XILV5K1N$BSkLiSdQSyV6BeUP z42@@homz}(`Tkzt=GW#)1BV1Wd?^s|*Zl!z`nadwtzmQF7)UKFUPdS^*I4J&OU0_~ z&m?Zd@8=N23;97FqM4fZ31{SfAMoVW*1l1$We zO5CKS1e=&od4SXG{PTt~+FzYrjRMn)0KLM0*^f-Wy}3rw`{1#CR+cZWf__A!S9U-r zCNA0YAKq9|c1$rPSnqR+Dic7jGO{i53T=rvku@SYG0v^lyrw=@7|`kHA3Qtj&VdQ`7_A+c>P zBQT%i~y@ro+@nZr7!Z|*!H&ilA2w@cLx+24dtY7t~3pXI3fK| z=xEnJ8`m!hm@RIR8D3_huuN(5uGmP)+Ih$;UtIJ~7<8`jnTB=qi}ll+gW`)I89);= z<|~CMmsvVI1UVF2t>v?yCbnFc&g7QwR5Wk-ht7RT626jMcSlysj??W2pKZ`{Vn}e2 z_3}>VzbBtEb8ks%!zSOEdv9XNy2r;p)-4;nSH{_8My&EJ2< zi0CG0=L@fSuo&NO9bc^CvvFm3_s{eOqoACeoc(uI(-PV%^?6{xW}>nF9X@J#q5)?% zN5NAFW*_P`auD3i(O5@jQhBP!LiuBjNrn;p*CShQX+Sa z`_|zAB)|KlTvzIGs0XP=A9Hbqc5sBMb^__NaK>DM3bHv^pV{YxJv*?r*2P1uK8-Gf zft7LwJ||wAj&}o3)@{lqSg{AJ@?D-kF#5N&IM2GXFU#e5i1vuT;c@lF7yXcyUcw)8 z|9@!zadidBq6K)NY|^C~CkU>tPj^m|nRE{~MhmINR6FN^MsBTqMIkn?c6j>?&uii3 l3P_?3MVb72|AwRwAYR;@LmF>}@&qpqKs#a_YU~1T{|7$WWd8sF literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/action-disconnect-light.png b/artifacts/icon-family-v1/png/action-disconnect-light.png new file mode 100644 index 0000000000000000000000000000000000000000..9beed0abc6d32caca0e0992ef0a69a1e6d9ecdde GIT binary patch literal 1846 zcmV-62g&$}P)lmIG1P4m{ne$!1;cz${4u|7vL~IE+wg#NE)i5+t0HUXOh&a=MS6qEsYLyAK~_rxF<_2r zW2F;VwbXY5@>Cluoj|IkzW)d0sWw(RfmBO9tqH&Jx{bsMgG{-+Ie3f+9eQc>$+c5 zUj!n#+GNo{MotIQBes5hBsTi)5YUpRl_K)fdd+N2rBXTHoPs2gNGu*_@sAbxHhIs5 zq|&L~YXIYS4uN$^Hm&OJP)`S$_b$`Z3Qty_`{3D;k&*L31 zwi33ahx)hqoXd>e2a7}#T{{K&N|D>Whw3ZpNv~(jNMxcaJu=dlDP{-pcu)OQ4NV#` zD+IX{)pfviMP;G7BRxE@5zwNxD}vx>$gE!~qI6{hw) z{8N>0-EfV!I?R&~7Uu~!^z_u#Wz0sDZz!y?l*X{CY&T~XKYQxbu3Y7lK(S`POd41B zw0LUn#c&ToJ9)lH7f2S^hp@|t_tMFOeTM_mDVVY_U?%a7j*m@FRNv`|u2EqHDlyLyRTkBerPiJ{&gOGKy# zP$lD`(xruuDdJyAo=Axmer>-`mze9Dy9N|#cjti|n zAn)u+)eW^7Gtk_UYz#V&=9Xk*ZN?1bIQbCr+HvJGJY8us5r(6Qu7?Qb&Xj1P>md_i z7^N+M{g*^}Jc2G~j~esHi9>_0`=K3O)p@IU@=K7;0-A^V2nzL2IGX5wSkPZk*qvv9 z7f{`n9v(PSlHRJ$TgCH!0DQSnO+_9(k=p%qDSD+4`fF&ct?PbNo`a8S`Gugc4`hc# zbXWR7|3C8Xe@*f;nw7gj9~8K)h}1HOZb%Oe{JDs27L1*xi(9)^BJwBT<`Oo43uOe+ zH$l!!|F#s-22@s1+IXN*RKHN_owg9H^@!cl-hORls`hE%0b4mtvol*Y@$jkr`_IhZ z)PJmZNyb`}40)DWZg>$YV<+D{O8}NkKVZaQ_o~0vJ_|~_>01T zZm&77Up)5ufbTP2ipBaJFq6jCWV45UACa%(|HWYxc^Q-4;@9h~AC#2=7l^gp9uxI8 zDe@r2j%dD|_XXXdVt$(*+LQJpKR+o;11=Dc$7?1REx$ulKM&jm#F#&41=7H)D)N`= zvtxe^YvM;Kl(hk~S-JAACFg6-J*CPcbHzpYRn7Uj$BrC%)%OY2K~X-npaPgavH2!T zk5$sihYB;`O2ipp8E1fHoB@_`23W=!U>RqCWt;()aRyk%8DJS_fMqJq05$qyDY0^; z;tcSNyu?RiN@p`Q9jhp;cS#n@*gK~`Sbk%}7_g3u7tj>Q=HrL@U$K~4NmNvSz)Wlp kD|a{?4u`|xa4dxX137(kf9;Z4f&c&j07*qoM6N<$f@_SCod5s; literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/action-import-dark.png b/artifacts/icon-family-v1/png/action-import-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..8c8828c92d4f5bb6e87932cc3c32cce9662f5458 GIT binary patch literal 969 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGoY)RhkE)4%caKYZ?lNlJ8>pWc? zLn`LHox9sl+EJwK|KRHH;tZ_hs z66VhLs@H=y)a}1-^^a$=;01ZLYQZl~im|OF$}f(F{`p)Q`H}tOi>oz%{u$iV*8aDD ziXO4p{6IZ19vrK_wHkmu&ZTfBby2$w~1CE3U4X`@A=pCH;59n(tR*RvgdA~5UGsqhlBpgFg%?>l&sW5@e_c4uo#S4Y}69{O1_ zrRr8-$)%37zkgl|*x`4>^={s@7RFyJO7Gw0U;p0lr)Xx){nC@I?hW0$?&>HrD(&Xq zetO;MC(Qp|PvYh-2;F`=>zaR%?wJFd=j1Xh;Fhj6=!%N!O0l&)3`~1A?3!J)EgQY7`6@4}>tK$ZwZ_ z)x-KrZOaqpw)IOz76QZN`=g87Z^!drZ~m2DYuqHlaK|Q+`NPRw@~)hDTv29t(#o;- z<&G0`_#Zu4dtG9mV2<u36w)8`^Yf9tJEne%tT?KLg#ivF>4H+OM-sXk#p*8`L- fzJO9yI@%n3GJ0A!Hna$H*>}2m zzmM`;nb3I3i#thY&6&dfqi+vo`I)|J8ctv*+%7Zk~VooG^nEhhmF>(}~i< z8RiQ#HWz>VvY^kMA;9|R@8-SdHkQrq5?IpUb|s1_MfyO{J1G; z>K~@}Vu|5GYAo@+r&zDBJ(F$tmwNrivPpk|Hg-gif;cUR?YFk(9P{R`59-f8SUz`pOcl$G6SvPA3%P8lNZgrl zG3^86_sWw?S#O-W?F+O-hugSeW>e~6GskP6*Ql@iJZW#0fc34nd8tzZI!d;GzIF9) z_k*bn2j;TKH}h9$Fi3cv*rb-CdN->|yyieKqr*DWhe4mt{S1A)mSMpkj}JSa_kW0D z2&hr{aqqKxg+9Xxdm*P6Kb4yV7*gsZPJf>8l=&bBgPJ#o?hl6qriO_uk;nGym;Pdy z*D6-y@G-(ma#CD*dYRt82ZuLK+Qg#C;BkKqWB!)gfzuu=Td87>hd*l-`Lde@Bg=>^!Yo^hV~tH!BN1Zd~*7^gTe~DWM4f(B`%4 literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/action-logs-dark.png b/artifacts/icon-family-v1/png/action-logs-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..240e9d0cad83ba7e040ba787a1a88e8a4944ed54 GIT binary patch literal 875 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGoY)RhkE)4%caKYZ?lNlJ86+B%W zLn`LHox3+r*ioeQe2$Wf`0@_jPrny1psEz;sLl}*Z>>CzLy3Z|f?E$$6X zQ?@nl5s574u-qq7c)&>|^7iK9WAi?5jXN9jUj6>vxsUI%wg@{16ui|gei#XsF;?A?LZoVNCRSxY}T8aGM*3Y&X)WB=E`nG3l)Ud%JnfBpNillTOy5=Ozb_xX=+ zWogw@nDq7cLdmEez{x9{jy-g`|uNfjVHXILb8xF{Sl}eSz^0++Qv*kUoB-n~W)@a74Q@;)VBR>ij`i->Gut8xZ@8XR zpLy2lg}B9?zh|~dtSorWoaI;o^kq4t;{2P(jvX)ms;981XM5J3loR(@T_$}D>)p;{ vdE|9YbK0KJ&+5*7U%u`DCtjzHA3u3p730^d&vI=7<{k!5S3j3^P63L2Xk&-5=xK>3fRzU0ZE!{#&y={rS5$Oimn%Edov* z7Yrg<*M&Sjn!?A=5OXf8NARcY-=nwJ&%b^DMCBYWH72jEzqAs}8PB8()-(NLxK=gy zn|GPgf8*y?2}`B)Z*i=Dc>W}N1IK~C+1%!Jva)hDDeA^PPplGzZnl4T{bYVZW777!;;HaI`$NJFK4JgWY4p zcMK77PY-;V)sVM*@5DmC^hv83k~iGFo4Y>U((Py2p1ijiObwH>4=sHc_d0S~c`OdXkmB7{^DINDk+u)K*cak#g6@d6f!=J0Db+{I<5KR+84z{HSHU;g~3hftB0 z`$0~IKa+qqACTuf$i?tyg1{Dr27Sc}MuzaF>AjQBc)TfEDQ0i?)tozGhCbW3Yn6(Z zez(}K6Z_C4l+YW=xS{CUd$zJI77m-Ylx)9$`*x*auAi3U={c(}SjJ9ou=C(1tyY@bvw~CWX7K_zi znLAd4H{2v&;GPAIv>2PB@;lUsY7W@>;ZS{U`?!HMk zQfHj8+dgf5L-)O#&y>v$Pv&32auMjYbF5E(o-;Gk`xo|{$>!C^wBE^bn?C1z%GKKc zC@g*WOt7I^Bd_x{^RkP7uhg06F0ipnpIzQ>p3PVL&t{zfI7uI>|Hs(A(m!K^e#=T= P&SLO%^>bP0l+XkK21AF3 literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/action-password-dark.png b/artifacts/icon-family-v1/png/action-password-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..a8b579a6d4ca36c682ea0667a8692278669f4f4b GIT binary patch literal 1919 zcmV-_2Y~pAP)Eg}$;>c)jJ%F73VogpE*Fkpm47p@>m5K5vU5vc}ZXlJ-HgVQ@LgtpARpNlC$ zo1Xi=^E|(#t8?!6eRKXfukW0b0uqTtB9TZW5{X12kw_$xT7in`jF}^;)Wk}YlmRB{ z0eI0|7U?cRrhlM!=zTUS@toiOZ|g1`jOH2o1n z!H)nQ4a%l~%ZkApySqF74%tsp2t9c>tf8 zGgGJg`}^-MRAFpvtVwBXdlAe-0M^;qTWu$$P>tO->-3sST|= zz4|CMo_at!oo=~@`Xt0V+*BPRtNk?o|BR*dWqHCy0E-1xbk&^htHcS}QxBL$-DX&% z7l^SVsKy5hJ%PcyEviIKYT6W(zhdG^00LgNC_e9Y!gWIL(&%vjmqq0aYzf+DF>oya zGe-b=T3CVTb6*h&&5}t(AB)R*Ju|Ce_zn}-0;EzCD*?0#il@!#$y5G95~CP*PXU-& zsEmPjEqi+)EZqW%;jKVlBE$*Ip_1$FF@fWOHju6!(TW~0$`yJCPf%q zx#C&?0*en<2>YkWZ3?L#{Ce) zoD`N3R{9IaQ2>MDB2yS!x#C&?h0Rfm;aCEYUQr8BA+L64d4s=@#F%Q+MiA;3DkC7*)!9=00u(My(OF>y=Fl>eCiB}uw?t=%$Oy}K zSa@0mF`FkWir0;&_01mR5t7K{wh|y7et>U+_E`-4q@xoMrzCDg7>~!}(d*trd%%s9 zzFZ|-fFK=BKu$5Idut{gJ$GI3s6~|}d4*12%VvFF%(|A%wyO%Ag7_=|01j7T;{!f6 zVv3<20H6yiFt2Jf)N`qnzRatS8!3HxqoJO&Jd$K&%~|D;S0AOuvjE-Qtr;-AXIY7P zRi1EhJUy|EnO*rxWO7?o!Udc2V6cMWzP`55Qy^jCD;3cbYdgw--Qmk(0v$_ca=#`s zxmT_B37V!gCo{R%5@~$|%wNNL*Z}~LDV&EYf&eaNY0ZYx_%ndj4nLUzXoQ)s5McrU zn9)H*g8;7q(BL`<#@^m|bieEG%78$wCML7lhmfaV7}OnvJx^4q2!UindpbLB7>cn5 zz@;GUd4jMnk<#~+%)dthOGo!FS(2E&)BY5gzY5BxYY6+2X??h4{yh-J0}V=M^w$CU z06cdqjg1SPn5>S#+uZI)}0Kz z3n1#n1_3z$hs{~#(EX)mBBk#EVV~{CE<{MAb8i8B5DzXZ=b16o7mr$PHUlB_M|zs3 zHJjA5i4|-n=4Tu{Thc)|L!c9iare80cDO-`U|}n7f(FCx3B`V5&l{|K?>9y}iaG>^g`43BfPJqiR2u4y zwc9;D@l90-00caw6meHwH39&@cxGZ3F&*?{gMi_lSoEWyVshZGy71K#N{~;gIspKW zB9thZSCs+)E=4F|Cbg*hfMVi!pWu<8az|C$1MXAqxudEV04VR=QAO{Bo#J)JJRch& zBPy9MxQ(qQ1OWVt5LWJ}W&{ArGj~)IbHIGcDR)$p0s!TcJE~a$fbz&4)wBRW>2pUl zF91;5+>sPuj#A~0YHAs3h2te^z{nmjk1%paR!9LBpqL^^0R$9F1UUx?=#5ABGx0mN z6@6X^mOa1*=c^-`iU~VnNxW2rqJq>)?UNf*U<3n7mDXWVw?q|A zR3{^ZkObTJw}*r^MLGBXwXf~-dGtB=_xt63bIv`#-#G`6NF)-8L?V$$Boc{4B9YVz zR7z)wL_(dqg$Sb<1|!6v4FEvI^8m7h!05IHWRl5bp_Flz6VC`XM|*K0oo(*S|{ z0BkaNo@tpqv^RN#620#&Y7B0BzAnnp8D#7(@qP{L)3t0XSCF_~_V`)VD5% z=Nr5bKys|Rqw;1*$oM#Pxxm}k(^UeA53u|@R@$kdz8}jR()0htuu-Cw1*HUol9{_%a z3jQ!V8Uc~+eZOI*xApokFr^T`l)04pz>4i~tZx9|V*s}5b|n0I^wQwpt=RSxwgp(3 zdagllsmT~p1IjZaL&-@yK011OTcHKc5V%vP+c)#;@*Sd4<#!aj52|Y5F!WwN;S$yt zAG7=N0pQxu*{=%-{+K}{I^A|`xD))HT_5Gf)(GhAOf(egwd)XMxC~4M6{X9`%U?}L zPj4$}%0&QM1YK^_J}mZ?h`aG-VPQ{I}1t7x_td<084`A&Fy28VXu69g=GO4Md2Swgo|D- z2bVvxJS1vYNU44Szz7MOG<@YK8WRxoe6TP!zhXlGMY#H5g{K`wV*(9IPSmCli>5~3 zVmlF&xPx^8NSo7X)UVsPfC5eELu0z>wSTvhWH#sm!7Ep8=YY<|VE0EED( zsErwWVzJl;XCaA+M*BAc=n=JRtO;ZDE0zV=)_@EE(NM3SqYckE3rWnK;Nr6Y)(M(t z$J+0&egTrnWC4WFgdLbXt4uQEkWObfa%?ip59iwLETGx?9n!6*4ufTT`5yk9JT~lIWG9F zPM59F0%uxdk2^k?)f#(zvx4Gji1z{j#ygd`7XUa&#EKdp1#m;uPT)=z`Olqw{IdOYSsAZ0TpNRSp&_qnXXbd$^<+9^nz{2T;NO#|h z1nm?7&3gTa@N#A-nX(YNuW))Uh{6xWPk{>1aW%z|;0)ZouEL&?;1cH&%PsCgd77eFjcN0HdR-?Bny06Y!g zDOPY`Yp5kRogKeqGj7v(eo1e6X}Rz`i1q_W!1&tI4SW~!QQh+t@g z`Q_2esXrU}a6)MXa2Y2en0mGZ0#w{dveo3WvDCWR{~8Xd|_j?cIftbmFh0e7)7 z5&*zlUp|;gr*to$xItA20GJoS45iGfD|!lAO)firZp)8$-XzeIPV5l))l52Nm}|I2 z)d&Cp)7K|1nEWQJ$?|`G>0UliWdZ<}KFr^vT*bVq69BL-LOCm`PVWi(mP~r^NF)|F zwc@dZTeYLA907N+nk|1pwR^VR^YrZ{hm~8WaFeHf?Ku&uZdU^#TCyiC~ax zC`|nIbavu`mDp1Qi>o25MUusaC9J83ZR4OJc007V`%40E<172st+lE0p_P8dP438c!Wt2 z1gK+Ku_Sif8YW@2Qya&Ke1}BX7>Y}Qm!ja p5{X12kw_#Gi9{liNFpfi@ zLn`LHox9)fc7RBG{qd9+ZIT{Wrtrva+R}ev>dL#n`E*1Ux=o$2YXRTFtW$?3PwCuP z+p@_(ZAq8pqnuFDBC81s|5Udfy#C$l`}ecQzsJq>-?yo@ri9UnL$O7`sU!bHvi=*l z#m~6Z@dN1yc7tDBXcn;u=v@`df=G!8z-kfJ#MsAH>c+*{G=KJD50 z-ZM!rpLVF&-;7e6=)7FX*pknWwu|0f|J(BpZHK)s3W{_jj;*LJYxUKZLTKA|I#^B(t% zYg3PNH}iOXh;vxHt4eLr+9M9mKuHFMuV1(Jb-hz#BhgG3je+@5|djZdCik?uj3xo3(l=Ow%T1SDQqhHpJcIa{rb{LPIGTJJ*%0o zFT3i}JGaGYL34_kWL`N|YptxhF-Q1;^f^wCueJMRmb^+V_5-GG3$-!9>V^>MuWQzU0I2^q|+XjC)*cIeX6R>d+$Eu-HaqeOL*BiFrJj~0g~OX`P(M*2OQY*>u|&Z>t&PqKWK6sc>9alAUl|sJ2QA` zgXXqZ{P*%5x4~l?TLSp>S4`x@?9Uqiro5g}9X ja#9_bHGui!$I1GYv+94i1?_qX%$y9Ku6{1-oD!M<`O&ft literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/action-quit-light.png b/artifacts/icon-family-v1/png/action-quit-light.png new file mode 100644 index 0000000000000000000000000000000000000000..1bc59b18159f9f07f7550795a55d27875a1e8a22 GIT binary patch literal 976 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGoY)RhkE)4%caKYZ?lNlJ8TRmMI zLn`LHookqX*+HW1zPFKq(S`#o&YsNPA^j`P1#xng{d1lk5bEMFH$tmTL~z%a=?yJc zmU8C!zI2*>p>rjVXp+l`uZBllm-;>`e*L+;?|!=7{n&l#c60y!yv*1l;KZTWGGWoe zbybOL-<@wwwP7q!KKgUUhutMz{O!N*F77$L_0Uw7kiEx@7ML@J1kLN$WLz-o@V|4@ zF8o+IF~Z@?dHaT#59c|&mRC&pZoP2Im!=I%<~!N_UZK3r}e!B^q7?y6Zz43OR*XHw) z>g&BPoN-`06wqKGqQJw-;f&7IQwf{%Af`_`^4Xk9_Jk>q`!21KWth96r+L+L`}0X} z4soxz`gfnB9@MKkB#7UI%Z-~*GVwAnA;x-li7f)VIj<&3*s z+3DU+4_O%w6s*5~(QEy&t(P6D>lSXD_Uwj;z{lL}->-QzU3#7AwVE+Ab&j)O1>4(Q z5?41^sxQc}P(SeGZ;hY9s>EWy123{!uDaY)&A4mybJL-dTgz_Tzq#t_-?tgkRnb*; z&nws-#KkDHZee4yRyYvIc;M#ThVo0FEgtW?9uazh?cnw7=DPDQBpC_{IEyA~{K$WF z%k^OW+$H&39S74sFmlc4di#J`#9*RM6Mw*gh)rB}4vf=J82w;i{o{V^AiKr`d7*>s zGIau{C%roKh^wcmKWtLFjxbj}`;}M!WTs>t-zv>|U+47HmP6bIC+%;5bZ@-D10;h# z^KWYgnz-bTGeg4BvJZ^!niyhE*{4J;^I{YX`q_R+-|-U8=oV4%+4a83>F+V{pE=55epLrg_P@8!zq_-V>4D*sX&V><&K{ip&VAv>VCCM&Ih)r#w3@dx iS3?n;J(g7bVU_f2dZGQZyA7B{89ZJ6T-G@yGywqb>9iC8 literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/action-refresh-dark.png b/artifacts/icon-family-v1/png/action-refresh-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..3543a8ddc17f407ec1e59c08af6110f197fdea0d GIT binary patch literal 2465 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 literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/action-refresh-light.png b/artifacts/icon-family-v1/png/action-refresh-light.png new file mode 100644 index 0000000000000000000000000000000000000000..89a0c4d8592b688c942ff08c59c3d2f3d0e91510 GIT binary patch literal 2501 zcmV;$2|D(PP){B~z&XJ+RBi9{liNF)-8L?V$$BofKz z1u8UQ#Rz?v?Zcx0pro<&$N}T1I9b`zG_B|L>pi-)|LxGB`i}wFUg~g4K><*;$nyZN z0N}szQwpGYmRY+>oU}GHP3w6Xy~fy}C;`JjTna`hfPNjAUjyhQz{eSUoQMwi+1}M; z*8g3!E>YwifE!o-VSHNoH%TdJd|AYuP@z>1N`qz)V#_UZApGE3pd}d$>(k+&L*j&D1wc_X{fA)RhX7(l z(r}Z(#8?{&>ot|ym@j$l-17jG4IkY-l%fasJmNJC1nbu z9N>qTF%Cd54?q1F*rsaL3oWy52|Va6c@_Xwi+q)B-V7kuhu$>+zbA#?NR$q&|7>NW z;r0Ygd-q-daN)+;^#BkW5iPZS_EQ8r46_@us^4Sgqf-qSp%2r$n^k( zs>Vzrg*F4|nZ?uw<4pw|w9LB2Nwem>P$3&PrW0{vQ^GXDM0gHB4*B!5A+35fTG+j)29Xa5Ulb zV$8{EO!QWwtp7J^YHCs6fB?i@gJgzJs=_DI*N}l{K{g zGfsLpqDeLyTZt)#Ox;exBcZA>lSKLz-2~+_h_)hW*3Rlmm4A~&ymm7)7G<)rNqMcj z{1K2u`;QU1INKnoE+nP{wA>5)Gt z*nUNs0pOF)3<&%^P1A%7nR_!7LHIK>m8-e+r(23K$K0N#hMKc#IIYSEBWKV3Bdz^8M}MWcIbkM#g9c5<4C(-WQg$U6XRb7zA7 z?>KmH=Vbuv-1L!m02G_v1>nWoYwCutqN1d+5*?RUh(2Gw3C^EAb)nzj((?c&z`Z6c z1<<_2eq)DA`R7b0U1fs0p_P@DC8_RxPXQR%iODAce;`=IuOagy6t14eOm892cLpN7 znrJi@=95OqL%6A_={kclUE#f3Q?2Vn`E!#{xcWtA+5qt{Y#k!3LheNK>i}69OvVSR z^jAdra{&s4^@YszIy}5kggG)zvz0jg-Apz_m>;T&ww!V7@%rXv}rv<8oIDpJ=G7CGh+#WsY}SBdQ@R-++&gO2vNdHZw1ta}bXE(PezjMbqN=Ndxc>S@tvROsmCy$_5X zplXptzLae-Fdf;;eHn~NiFo}MkvclU?O|HmGL1QEl};ec%x28MNHG2G%q9DDs4B9` z_NCuWHq@Ue$a5^_Q%`)P6Jt(ms&y)Wk{nYu+cq9My5BGg@|!1KjFa0|+?XBIBBuzv z0J+_DLzs9e*~-$OrXN!XI{?~a!#=JkCC3wg-Tklj#?ffhfA%7Vu#blVJRFR#;l#NJ zfIghxV9P&j*s-Jg>-XiA$^l+&TWKfF+C`zN>U~V~8vuQCO-MjFx9tP^0)fEkR;ZfZ zjCLhi|q21wV2VMrg zZ<)p<;X5_vfaiViBm3Vwm1r~~#Pm48r@Z#x9%A0*Q_>@orm+k~`cHwPjZP-wwVS)O z_NWA~1i;50yFUQN*hIW;+~I~jO&jg=CUxuZ%+W(J0EE`5B;4I2vKtPk=E2K!wBnS^&Hc=Iwz%$vP1eLZX-9 zbhQB7LfQTL7yXQJV0?vuG6u>33`NKPDf1D4lOX&JOi8xw+AG~t@1NegSLomwAa)^I zmkvND(0%ufxn=oBNy*h~rfFXBQbbo@iYbvuBoc{4B9TZW5{X12>3aMJOLU6Crk;4L P00000NkvXXu0mjfY*oE1 literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/format-clock-dark.png b/artifacts/icon-family-v1/png/format-clock-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..2bf66319734062556c79d53693a2ae65250aee37 GIT binary patch literal 3152 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 literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/format-ring-light.png b/artifacts/icon-family-v1/png/format-ring-light.png new file mode 100644 index 0000000000000000000000000000000000000000..603836de484dbc6e6263acb24b901c6c8664cf73 GIT binary patch literal 4087 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 literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/format-shield-dark.png b/artifacts/icon-family-v1/png/format-shield-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..4f075e1778590d614bee12d0cdea36e2c0afe87f GIT binary patch literal 3549 zcmV<34I=W1P)?rzfVZuaip&E4RB{_`t3leJoxCA79r?D z0076q=dW4b{2~I2#wgW%Dt9|uX{q)lflR|)X8=jg;s9j5d z^G*)iQ`f&BrX`z4pEDh8Zz!dI{*JEIPfnbdrBT%a^gh0A3X`e_P+gIJ+@wJOJQj+z zz7;rnVeZsO0jcc@ImYL1U%c`k6X9+g=Z%UvT_RN_z{5{$ou;H*4ggDX6+A=ah)hQ$wkQ0~xhJ%d zmSSxqp$t0uW&`xw?p(C;MNb_sgQ^hV;XiLaTXEh^q!t1oKRFx`8E2>gfJmPk(h|{q zfurXnxE*zq7Xqq))L#fl{LvllJr8)`ep&b?!0(@UA{3_JVx^#)09td!K}3dt8e`dl zPs0EcX2|T@tsUw*j3;^&kmlA0O^JbkqpyvC{oNbeukocFF`)wdqOUL5!0RsN$QBaN zJR-FwPXP{C9iBXJfJI2#nr zA%rR8IDm-AIb#|Dv0QOD=lkj-p+C);b^7jN{8+zl+b8!UE*QB;r zL;gIMe6x|_8@;?kN*3VJC$~?xQuf6_&WY+KB{>j7g#0_z7%_t>(K7_)!AaRr{JS2#}%7Fdq%k8VTmtw0V0eUz5wHpzx z1Ax4Rmm?#@{}wt2$nk8?#6!h7f4ROcvg!S;EpL_L-^ujt-}#Y#b>fR7JT)80{X3!v zC~5_N_SN=}-RL%(Ccpr>Y`2Q<#27nw9Ib!a|OEx|Znx?*W=8TptQzF3= zZv85TEpPwx18*jd+%(8WIvl1Q$KMMer6@Vdz)TjdGoCV!kKuZ&Bx2fs>IBRC}%cdDfx%Hu3n#@3I z)vSg01Hk=z1`aj8IQ-_P2Wg}`&g@x)RPk#8}~X_|3tPScEg0pQ-lv17sQ$6sH1!isl~u;lqE<`h+_C&(Zv5Kc`0aDD#Ob;4niTTHz*tBwORx=E- z=s5{R+4Is^4fnVfKte^wPW|8ES^!2kW=szejT-jGs$#}XB_S#_BomWv?YR~}5sb+M z0aeym>7&Xf3q<+fn~Wgl)}CttxWKVP2`MW8$l^y!PgCkaNik&s?9xFvaQ!bI-6rK>7EB z@z-42bejMXi3l@y0Vft89Uinr#I4QA0y>a)u9;A5@Q*z`t{X`uwuIH|83TmFK$vL@ z=#KuL6+j{6opmWBcYXB(lqdiqWHTd_NRW9C7^JycI$$zkgOhg#j1FQ)DK<+IfP=PY z>~A)lKGrN2eJ{QTm}GS}a{~FoF$Is6WVe(=FYQ=x0Dv-eUal}Rs}UJO#4;*AwP(VS zFgy2DLjX>gJhMxcv^Z2r0^EH!DkS_{#sS3!fwB#gx5KRS}bETV%CE|4 zEbTkx*e^?f6<2m11ftAJCPK2KsIr}N5nFE&l1;fB->+uqbs0af7hx9Qbk|D+ZY$!rwBGSeQ zC(Q^92F$R?Ic1gJ(S&T{n*f-va^xZ}5BS*9g)boBuJmst9O9B^KHLamfu@mgn-_Ua z1j?cgo8|BKH>I}s&c&@(Gp{cxrO3{ zZS#+JcC6m&Ri2(cm(Q3QTn7XPGscMx3Wa0Z22*3vbE>holu1^Xpwz-bb$*@1(I&&Z z&eMFoG&X;YTkeE1Vg-6` zn7=HZH%Tv_M7x?1Rz85*GE@Pg%aUugVA%DV!n$&5)CQoLpHaKLh%|b z^T&5AUiqxo`B$WBc=ggne?fxHnG=N4aQN$>vcnp65|Qb{(R0v85g0Ioq`ET2?1HOc z1s(lwUtWCm?UnJNLNo@QpE1B!(!UW{(o|y4=~;3Z6AgRPuy zi`fOgSqQ}k>yl>2-CaGdha48|OQj4004!hLKFm0M8v%}|&mpl9Q|hmc7C{gXppBPv z$#X7a?F5U~#9Ynw9BjZ$=ZmN+iq2udEMDntV zWkLWU$9TGh%oXK~<1 zYf-j~;lI0QM<{gttqYg!ENr2=m~;Z9`QhgE3scPb3;=+k#BbehpjM+sjT$v-_|1O+ Xv!}6AG_cy200000NkvXXu0mjf#lf8O literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/format-shield-light.png b/artifacts/icon-family-v1/png/format-shield-light.png new file mode 100644 index 0000000000000000000000000000000000000000..a77001b3e4a42a803955813a6daff2262e84f467 GIT binary patch literal 3665 zcmb7H_dDB<_kB@>Dz$1>sZo1Vqe|2)iBg-YSW#Q;Ev->%s}WmE)TmW6R!}3vXshsoKZO0)ekdgNjUhaMWtWPvr2v%ae=dj;I- zp`|0K|6c6au9f9oKh24>H!l12<;$31i*Dq7f$fwAiTK!9WT;+wzmvI%oeV1&9Y~~R zN|qWc>6uFeUmMK9&0mD%hjw@&S=MgVjzoHCjO>oiug_fstj$0sJ>w@-0~&>F*%-t-C3z?Vbu3eLEC+Aj}B{I+8m|*P0-86J;A# zmu@|nTv5NcP-cB%;ZS@(OICmcQK2M;S52Xg&+}Ct85^0}*Ktb1R>JC5nBlM-L7a=k z^l);&oG3(D;u#yVK{nV9-Ux}?y0FljdROQY;&-s`V1@D2U(-~ltbXPAMTNXZPii4I zVAc*Mo-010t3apda{ybXd!y>+VZ|Pasdbzh@w3c~CKx0WEAG7#cG5mKfL~Go&ah^< zs{%gKcj8_aDx#gIO^oDuyJ)o(9NoQgSyvF?K-{!99A!K} zta>*(IB+?j+~Ly0m0oMCq=U`cUb!KlC+p-rt3Q!p1aMoa86TJ)sO0EIlzbOCJoqFW zYCMg-9Czh$N{o26kd*qz+-ex~P3J8(Gu#izWue0mdHJy8^Ktbw3=id*X zuP!F}IM_La+y1USwSvm_hiS16kDc}EaNhYfuCJ5nZvI>mv)b>2!A*?sUEWE)NEf9V zA83XfAA+9PNJ?MPfWPUjiz7Rdw1wzrF(sKQ0!M$*wd~hHdxZp06uss*{F?H!3ID{R zB3Xq*%#YjQ>Rsb&*0Do#WP4HNtK~hds{4$;J2lO-wKiF@#(2o%xQkymLEsKpyMLOl zG*1(C7|nMMSJqzp?VWtXoxX|73)ya@r&Uaq{7JtrugpXi8&MkX8@~EFd=*6JIoB{= z|LCA5Edz*6?_K*q6Wf87a_5|afN<@oOqK7I>#Ykveq2p2egh?}(Jz2mcbkr#-BK|b z;yL{!*yI9MXpGvOQ0H_?nOF*&qAz zCvP5CMl39TpJ7y^1$VP@*MFMgW)1(0sti(e(4m zgQtRNr>BRR$Ilc-@^l$TpOx+n^Uq$}eR^GywU3t(}i;D)%;}W@2E?W`ia9`Xxi!Q4~iR%1);Y!U)?E{9(b%QaAO< zdj|gy@Kg!NiEx>d4 zFNq<5C#$VDNM`;=(IIAhIVVqp&I}=z4{1P=dSNrSxLN4oa}M;+MBjinhr+ix&g=hR z7}UC9!}Fvm_MhAX)kvK$r|$|(+O6g|!@uIYaAFsEuoM&ZIC2jA1}d!oLNl28%}52n zljJpyLJ2RJC?|zM<+dOQhQB?Z98Ez45q9yndj+1uh#JoMfj;<4Vyzy~#di486nL_P zpx6$AAbkWD$-Gc(tZe%=*%^Rsp(*oF8fqm|>$ZW)LGppy+vM3aNnG+Lxftw>h_(mIG&$nPEK5R$N!o02CM-{k4 z-c94FJ=}LY0;juNdp136fyl6xc-QF;KZZVB`jp72pCFydeCDdk*ss;);mN41Ixyev zx;o%rd5F{3dlwfKT)*31I)u06G{x4uwAE+o=La!PHLjEqh{2|26_Jx-T8N`(kLP>A zzP$9=alV~Q*$+0+@Ya6rMlC0b+K1M1wq7Vuy$?SAjFsYv8FVN%n`R(Hx=29cwXu8H9CN$|Hj!-GK8dJY)0?apnF865=ZHj_EYqZ~zfe zZTV5u4Am%REq0i=F-n$>sp6`3=qolDwOE@47Zg)!sGF;RWM0z%BoQnKSD*K%=#L^s zWcO)vveVsoOak>l)R@{!^hNAq`70BY;hGfZ@G(8fl#&Kyik6{X@R#)aLei>5V<#?# zW(n&eHZRn_f7)WKFUi6GlN|tBeBJPwN?w&J5ds~ND9#xEQZ1R^wP|Q4@9K7w;*m!l zbNA!ZVrWQv`A}X${3m-^B{wm3^*)3$n=|1}FSFx^gqyz`2HSfyGCG;I$VgHq`<>vo{HSyuv}w>$P_`f4R>tmnjv_}FE^+dmLz zX-m;W)}$vbGr8f5nus3RQ3$7MiBhf4-H^u_-lOG-aAi5>Kov=?H2cX29uCjo@>{AH zBvQY)DAh!Tk-@^?R&=PYX{Bf-0-1{I1k{+`{VVMBrGJYa1e?TLaV8+)y#}fqV@!@g zquv+VjVumj%WgT=GPP0~OHq^%0Yr79D29?c7GI^lOLL);$DQ?w^otU{e-aW z_^7Qk?KMY9n{(bLsq&?g2`V8n?ucBCDSWvy55?upDgSyM`FuYGTbauiXrkfgJQwHX>t z81ZK&p>TYs?%`IInHP-{o)9)G)@Vtta(A_~_-Vf-*6SNNS!-)M;VQKos!6+`0VW4h zx@wef)kCc}G3FIQhFDJ9uN1X7Te02w2LSo=f|y$pvb=LRYG$cAd`#Ki+X|s^SHbSj z9F?!^H|BELmSu;~el3QIbKGN1V!__&Laiz~_p|DLz2%FfEz{3Y>g2RiH=_ zP4Y8~AUZubUDmNSv0|sesA}BI-ROTVRxPp}9db4uf2RIIQSb=>G_CUKY^u4RPs~Y5 ze74hNE*a~LHx9(h-ekcUKm;`qw`%iDFZTjyulW)UhebPs#bMoSv)J2>b(I0dNMB0S z5($8iuW^sx)E|$1os2Yj6`}S!nkkTbBPP-!w6(oWj+Qa;Jp<>rFMNz4k913o1Qu87 zf#`~%QJg1F7G3FNa^?KsLk?r zMJ4uX{ni~Za13xBmxlCJGe* literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/format-time-dark.png b/artifacts/icon-family-v1/png/format-time-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..da1532fb8704201fa09d4483b264df3ea9642260 GIT binary patch literal 6717 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 T*)|J=00000NkvXXu0mjf4w0#W literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/format-time-light.png b/artifacts/icon-family-v1/png/format-time-light.png new file mode 100644 index 0000000000000000000000000000000000000000..03844047573cc0f9ebf402adcb626019fb8de236 GIT binary patch literal 6744 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 LNkvXXu0mjf_%K-8 literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/source-local-dark.png b/artifacts/icon-family-v1/png/source-local-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..d934ffd9512ede05d6b0ee1f3daff8460c490019 GIT binary patch literal 1185 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGoY)RhkE)4%caKYZ?lNlIT!aQ9Z zLn`LHy>mWa+Es-8!+Ys`S8dTpH;$Cmi7r|tGoh-XNW)`iLr7C5aac*gLOmoJmw)z!n}$&`W)mUgZc9Qc zYYO+UA2<`jzdL+Jf#`waeXqH1syyR=cIxu{-+FIM8|0(ct`wg5v!}7!?zNmK%bi=C zIbTZ_Uicbux&Pji`ojkz<4yaOn6{NM?S7-p@^~?a@#W-+k+R=UvNN!qo7eFoIR5J% zmH?pP92HmH*9IO~;Jr2N_on`+x^E5c-0xfx7k#h2QW(c9)q5@|=R>g9^mc~(3@`Mr zZ{!o7&+?*_;ph@MwP#Cj-h5fDx0ppwpRK{d{rSN;SN=?3s?J*%@Z)Hy4CmIc*Uo)s z)P$TiG+OdMn0H#@T)RTsT<^?S*{dhn8{BW7TkZMw<$GJ{=L{zveLUjkc6#eRi(~no zz9}DDvMcqwH&|KlI?P~G@L?8M#>jD*p(T^ykO@PgRD%KagwOm{vu(B)lICQ+{_7Ek zznbaNecyZLFdGkGvk9w`K@jzj@4-XZ^{BZCd-_NJrajM9s$t<*f2$U9r02WXsh|CmtyI`H$d;X#`0)M0 z$#T)i3!6QwogV2wl)34B;pBJ47iXXD`!Z?Ch9e9~X6B48?K^ZIYrO)B2{A|L_})FL zGVl5K-k(*s%okqCcRVv^b?e>R3VY^U>vx!Mu%qxou8b?oDuW+uulV(>f94e|-l5_5 zYSOL~LV+@E_3Pd!{o->_t(2)_JHTJNt#XaQo1*#W^B+sFYG+R7PqC4%+JCXKl_$?x z{OuZ@=$MEVPu_odJtNaeT$-+%)V>B+0V}4f#Kd5yPG|np$s$GXDEpEnERbQ!}BG7XQTMlqcdNwpZQVm zi~FrOLF0Qf^`GyT`O?b1Pi@b0ldo?avwN7Cu5X@G76!@NEC2uD?z!ka+e6>o16bxT Nc)I$ztaD0e0st*SAx!`P literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/source-local-light.png b/artifacts/icon-family-v1/png/source-local-light.png new file mode 100644 index 0000000000000000000000000000000000000000..9067b7eae8cadd3775b512e359c59c15ee94cfc4 GIT binary patch literal 1224 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGoY)RhkE)4%caKYZ?lNlITYCT;X zLn`LHy>mZ%cBlmVhxf&k*!2G}<|&sRzRF=Xw{(L^>A8(dQiU(_w!ZaR^9WfC z=ilbkouB>L_mf$E9fK2xVv7KnSQH&#e0Z|^X3ifL=UfVzzMB;5-kwnrY`C_VrTD0P zdY(!4+%ypf=EF0K6Qt4=uC~;Oe>ziAXKDX;>)V9YtTuD&UT&1jsbhSw)9ZDYhPuH)Vx$g0ygkMM8?Ly>c z2{mOrm1qc^Yf48n^cy~On9X^yu5e$n z*TcTDo*#jaYc4Y+x^Wfw&>o#RH2uqm{ydF@x;qy4_wKzlQEI!bj&y%R^e#rGUfyN? zGFvvZ3AYES|6X-p^q$;B-^->w`_<0~o>{m^_TFRXr|fN;#bL@lo%-w(>N^2aDF8x!dMA zIrWH9{h9OsbG0{X?w@tT-lS+6$76=&vnSrKdScl0`SiUv=GP|Yvger=qXGux6;|;TC_pYYP8`YS;W0^RC(oZCT&Kd^BBQ zcE0nLUDIz*+O8sdS!@B*E{+5F4>y)*?FWi=yi|7e7WW^llk%Osz}+^k5(MVv(IR_PW96LTe9_;tnrnr7ygAj6Vd#|S9FO_`$0o| zT-=PkLHUcm$!xef_tLH2TJ~QePih3X1no4QrQ7own}4z0HKF4+Mk(Sc@u c{y*&N!wfq#Z=QPrESeZRUHx3vIVCg!06iiyg#Z8m literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/source-manual-dark.png b/artifacts/icon-family-v1/png/source-manual-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..92aae30a369538e02dbe8f7235cfcbdf277beec6 GIT binary patch literal 1212 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGoY)RhkE)4%caKYZ?lNlIT3O!vM zLn`LHy|X`GI#q)G!~0^hg-V>yy|%{g<_l{7kgUxU8u*jDX&0lCf>=UgXUM`;Nu65T zyf`{_?j~epx~54PZV-CWWTiMY?A3$#PTA0X7FwYl?@u?JZ7BM_Z{L%W=bt}EzOR(u zUnhUN94H_j;H9~AN)R$JHMHmoi^|fykN5JO$hP}4DIl$HadM{X!+p%loqyGbbhrLi zI<)vncT9s{`ui_-Y~idm;s<6fE=g)KZQV4_`CZjco9(iy2XC+{Xs+!mXKe~)*c=#V z()>+hPua7Ohp!9w3nq&`_?SFz#>}t#m_PiBxI0_y$lSln-yKgsf6Dl_T3=~iP+HuF zeXV?T1_wWV-h9t@(lz;<*GxS1Wz!aa&8ZToSibY}?i}g-(3NY~)@456kz<_Ee`oW{ zP2XicbuYbiXPTx#{^Yj@KJFKI{Gd4a#UHna_seSM_&Cj6_`#P!-09FWK8qbp4~moR zf*CwBOUtDhRx>KvHtK|Xzw=)f6B+cr!rStL8Kb$vl0e;E`ZL#c^*nF**7x1*#Dioh zc6kOduXka867%Pts}laZo+Jse0MBNcSIq7bHJ=>>6DC`Zt3pzplffEexEScL`c| zRUMB$b1+`%2@3wD)9pWeg8z;Q$F zz|9Da{{PP|&C~C?@t(PD{-XS4s`qyQjWmF`{W6n^5BCHpr~9v6!ju1>-(^l+`L$u< z;b(U*YZ*uML9TK*pu74VePfj5Tok{k!q%+q;9)eYuo#ZyRa01hG|2 zJo0k`dqZo)_M4VRvsO2i?T-Ia-0a@)bD=RS!;9xLGT-rgWVt*%#hsyOpuVtexi9XM0nk^71}l!aphgU#s;!;|kZa#t)^O{wUPF zt6FMwzjxAuh;3_gN~@nMoLk*e|LgwgEpHYTL_gT#`2S#GPV`FDj1J8ATD$)-UK15i V-QFqq8CV=Kc)I$ztaD0e0sz`>Qq=$e literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/source-manual-light.png b/artifacts/icon-family-v1/png/source-manual-light.png new file mode 100644 index 0000000000000000000000000000000000000000..6042a52789b315766f760cd0eb845f5e39671cc6 GIT binary patch literal 1245 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 JPDHLkV1mXvz)}DJ literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/time-expired-dark.png b/artifacts/icon-family-v1/png/time-expired-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..141646d990ecfa82bae940d161a50a24232bff1d GIT binary patch literal 4095 zcmV9qP)RP*- zN~*^2SQQY^m{@UBl|S~sB$cGHshEwfyMP-baUBdXRY~QsiDpe8W)WBr8DJb>Mi^cq z^X~5ZJdgaLV-f7z)3^KH?xuD=|IM6pf9H44x9@pB0H&E{nrWu_Wd)VnfkNrq)%|6S z)5ib+94!6q!W|plEw@jFaLWnM)7?F@Zq$9f+P3dUAP@k603^mt-^C4+}3>J zrxm4tTr-|(-@frbludxXAMKf~BK+Md*Lqa->5Qh6k>sJ2uD;<& z^iLOU-FhYL^HESz0eZT-XPPPhS;J$$p788;Bp`IA2>?iI`mln~Aw{qW005WZDxbsZ zgl*3#H_kwj%#S21_q4-&VT5MC<~b+1dS7P0-&|slU$j-Fb+Mg3ESGQ&R$y zV+LnevxVD)G=k6XG(0C+Xc__|mXVc@TuC|L%ecGs$xS~i)K)%3DnQT6-7_`8ACVcm zPouO`qkgN*m{F`-yM+8( zlwU}}0u1cgw~A!!Z4&286wYSLj5b7(**9V-YKFguwwrzT^5L*QaaDLaG7wglRXOIZlIm!b802xgi2SQGoj9!ew zriDohaJJNN-0C>WT!D}nN|-Or-SPPEgnc%&Kj(MvT~nVLeK+dN_X%OPre0A5Kc#Xp z7NzY;TtsSIK+6ozX_Og@w4Wgm5<|(_FVEe+{^wzylfov1sJA()%;yLTTT#Y2A?Hm& z&n6jTQP>Sa6>LlecvmP2NfFYHD4lC~ZWZRmzYh`uA?j@gfOrMK2x`JUb0ZuhVJqqc z#pF^#@H2+sE^u0m$**X#wHB&Vv^JU zl>q>Fti^drkQvxA(0%~;v>7Z*FrjK|tE^0ORB6OI@HNfUObbwErUfW7(*l&4k~Bl} zfz{O}{pRLIfpMfg)SE$^Gx_4ht7K#}6=yp6QV{|;%a$#07cX1^2$f`h!fkI8YH#0B z?c~X_&k>is2x4`$$x>!M001C_+{Fu5u)5lU=MAEw>;m|6<}{Tw^Cv+F`E%wpl|0>> zD7yf^?37&q`O>8;AVld$D1;F5rAuX*h`*7t3qVFjQ)+MD(UOWFgiw3?j#ffTs3KZH z+R2mW>-Otbsy+a`xPDWpMCvC1gH8 zg$Mxf>6bu8MnCkL8e4cGQI{=_&{f@d=lzqy_p^@l2}PDt4?q0%pfpfAJ)$4~;KQhV zj)JlmK{ule4hBxZ3q>{U&W^!Fako(9&x=o_s*=6x zt~COo!1q!52TmcHz33_@l_vlIXeUpfC7Dd%$_TD&NqhC`FHQcPUVYaJu4##&_}H?? z^;4(IKJ1Wb15uyKQYPbk?kSIjjl&`0-x==M^~{S~0Dl zn~?`Ef1)%E_IWKWf#tf>*|ADYv2#Wl9Q;tabUA0!wVYJu7w{SSkz*%tCNmloE(n%^ zkiZ`iN~cG)UmWX+$Gd0dy)m@P5AZs z0(n7UD26WzUmu!K&YTIorAY1l@O?5gJQ1}&2y$$lLdXegFLZ_>jM712LWo%E6zxRM zS#s@@!F=PBYu7GlF|~TQK*2>G1m{f<;lF?!0w5@S^Tkw{2M-=5mNn&~U6jd;C4c_j z;kf+B^^P1w2?P)j_*r8i`@MxiTrfiSUGuf9h}a%2qyH^;kqn2dM*eOKuINWL3>HaWePmW6)v?AxO7NoF+g$KVn9P$4!85`bapr$J%5@9QopvL3(~ zxpyqTGgqrqzI^4J(m!xXJ==d#y87`z4r|E1qhqBYxTs#bhjF#;d3sQ|BXD4z~+_=tqyehdlrDO=igR zsea_hLBx6Bz?<7Te@QVFvh1_KRdg9uJ%+l%SHJ*844!2q`OTm(!*flCkb){>dvW`G zE-Qhbx;k+FlzjE-@Xi01KE5`hTo??V%9It&ThunU5T7h8%``kWaJRiH%litk3s8gr z2$UZSi~?IARKU_g?D{P&f#<>@*UhLWjt6G4e*A;e$a6D6;a(2gxnP0^z6(d#Pmrot z3b6}NqgN6%-gZ)FKk)KdV&=IK+<*UQiRMeHl0$F!nifzxPiTTOHr=0 zKDFV6V$&&F0ECd3F!Y?|pzive2vF8x+)CUZz!6e4&+p9j__%8P0RSr6??@)m=WpBe zQbth&Cu(HsD=Ccb%@$UP`vWXM>l7M1w~Mf_T&+6Jnp~Oh%F1;K&)6Dex{(Udu=QK1QPX^sVH7wp zB{L=o#_s2c#4~|k06qbo`}BS($5}uOBQ{)>=xW;Wjl6pH`4ag`w$>*%{cPAwyp$`B z=6RY+{Rb(+v7bma6%>R@srahy=RO^4L{EIbZS(s7jynC=IzU%neC0@$Yp=`|$5Pac zjKy0LpsaHXal;W(UB(|YJTK>Yr{kJ_r0KV}tct^j*j7girQu#nQ7`0*V|cFVb9mS% zC~$K{T=*CpF5?ePmHC#UUK~Y<`{VK>HUXM;e8U>nm0xuU$+=q0@H`D%_B9uiNam9B z!6T#=dGsM8#}p#~fJ>zDA=zBF^qH>EOAhlT*8KsCwmtUINHXztpOBmtmqL9-a^0_3 zM9zEhRiRi!x}7-gS7hodx#IbRSi=ePp~X+HKOd(*B^d-ez4P^TP4>jU%Z%sz#R-f= z$}swpl*V$y#RQh_ta7Y2G{xDV6cguavg(mV+cvxthaWdmvQfyhyZ`RN+tMTdBym1v z%V$E@hpL3wFF*v&xP^g&P#qxal8!y)MG*`U=VP<#o5c<@=SxY4fqP%xd*7_g_&+O@ zO zWK#d7QkwNRf*TPCi3#1fkmUYh6tEsO@L3QzjiuE|$8MRb$N>OwC3$GLs^;FdEnTO> zq*E+qxkIMsmA%a~Q<(#%@6OF9zOBfPkmN&pz|9$7h>zt)V+v^rtijrpGN zK4O?}IdtNiZO=Yimd;?=udy1~`P%myGU@N+dv6#egl1H|FA2N{eRe#uzy#75E!S;l zQNH&AaD>@VGWor7-#b}$0RTR|=%?OI?G1CCm8B@QkmU~m0U+1wFnmAnc?3t2hpwB6 zM@!MnoQjGN005wW*S>0%W&W|&vhIs34Iu!=OyeC@t^2ixt>3DM1Dh&FfJx5(xcj%N z(-VJ|Pg6Av9+6VlP4oBLw{O}RrQKqwH~|0v`gV2KCw%vfYTJ6C=mjeXiBa9yZ)-+Z z+m^11J2Rpp1(>9N*H1Q7+ty#|)Gug*g{>&p#th?k7d*M~ji`N#ii#Eh06^^9N6wFV ze>5YNevXLzw!t!ty;0rVa~&^vX625Rkql?VMa2s+$>|@wetQ-2Uaq$72ZB~!a6o)a z)88I5v~A0`tdHalvbecr1em06=W87a=KtXT-Ln1J?b&uRxo!UAU9lZg5C^xM0F#{G xy>|^_{u2NIg2=Ciy+Cc6X{MQGnrX_-{{gwTWqTyKoZA2Z002ovPDHLkV1k_G-L3!t literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/time-expired-light.png b/artifacts/icon-family-v1/png/time-expired-light.png new file mode 100644 index 0000000000000000000000000000000000000000..83d6d2cd5c73f882e4710e053dad54754a45680e GIT binary patch literal 4086 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 literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/time-half-dark.png b/artifacts/icon-family-v1/png/time-half-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..d60654430b7b698c5f073faf10ac6bfc963d59ea GIT binary patch literal 3653 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 X-QM{xOgk|I00000NkvXXu0mjfa(?BW literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/time-half-light.png b/artifacts/icon-family-v1/png/time-half-light.png new file mode 100644 index 0000000000000000000000000000000000000000..e8788dd959e67cd035f42b518aa07d20a33f3964 GIT binary patch literal 3790 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 literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/time-hour-dark.png b/artifacts/icon-family-v1/png/time-hour-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..4bc76c00e50769293482ca710a65be862281ea2f GIT binary patch literal 3348 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 literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/time-quarter-dark.png b/artifacts/icon-family-v1/png/time-quarter-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..f078d76864bd99cd9dafdd0abd76980c1f39ff59 GIT binary patch literal 3881 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 literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/time-quarter-hour-dark.png b/artifacts/icon-family-v1/png/time-quarter-hour-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..1537de69e4d67dbcff8ce92ae10e3060d72a4c89 GIT binary patch literal 3232 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 Vz8H~`g54_v)Kzqps}ya+{|9wSH6j22 literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/time-quarter-light.png b/artifacts/icon-family-v1/png/time-quarter-light.png new file mode 100644 index 0000000000000000000000000000000000000000..a2e154ddc2625430f78197aaa669f1e24ac700f7 GIT binary patch literal 3954 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 literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/time-start-light.png b/artifacts/icon-family-v1/png/time-start-light.png new file mode 100644 index 0000000000000000000000000000000000000000..153c1a85d5385ac70eb1b7e9e259c59c0c7210de GIT binary patch literal 3868 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 literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/time-three-quarter-dark.png b/artifacts/icon-family-v1/png/time-three-quarter-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..f1cb2212154224ae8281f8ff93580fbf8fc72f92 GIT binary patch literal 3338 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 zri literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/time-three-quarter-light.png b/artifacts/icon-family-v1/png/time-three-quarter-light.png new file mode 100644 index 0000000000000000000000000000000000000000..98f3871309627e08049ada5b593f2c9774914ce2 GIT binary patch literal 3398 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 literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/time-unknown-dark.png b/artifacts/icon-family-v1/png/time-unknown-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..49f49041531a34c3879d3424eef9d22e29371a94 GIT binary patch literal 2865 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 wfK!ZKDECzWBgrqay+Ex@+TL1t6 literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/vpn-connecting-dark.png b/artifacts/icon-family-v1/png/vpn-connecting-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..47a191bf74cac8c1db3700214ce16838bb5a233a GIT binary patch literal 2852 zcmbuB_dnH-`^I0#IT=UxN{*3ahm6Q5;-nJ}$rc&MG2@u$D01xVdy!`4bwOrrbJfM8^$hXV>wP zx(6e42k6;!s<~9CDSn4*!%=l@aYcy=4m=D{(E?$IC=Lb`Bi&{B_lEtvHW(D}nXVdz zO(W%^RHYCT8(YCg1ih@L-{}8Ht&de7g()30tmdtT`Mqex{x@`z2j2fzN1dYf*e)q4 z=Z$;u-{ryhj4maT;J2_~l7z&t1~?`*wkORcP)THwo;~Z}-C5e!3cjPhy*+ez=y=w} zo}X~_mPI(#8_;5q;lpTi%>?z^3cvE7fhozKT@!{KB$|4F@e9ygFQ{8+psVYA?wgHF z0p-`Azq-11rmV-eA$*kL38PXskWiZ9j09(OtLG;zOSjwLhFP|yOXe-mUMvV^TKW}& zZ>3YG4ULXwx^bCwd!QWbR&#U9+9=e>xNS2j zlBcZUU@U&%Az)#_;Vh5Ol==#j{4o-z_s7=UZ6vOW{#?vw#W?cdogqbN2Gg<`e$XQ@ z8fVTmgT>x@P*L(k-Bv9j!WLp>^Uw=$2Q?9K<}%(sw|=Ooc3wzk89+1ZXYg32`N6`A zA^T!@xwq={fQUT=<7ugR*p{}E?N!JZvCf$H&7-r-Xcj@X zKNoZFU%f9JGKfC}(eM5xZEi|o-;^WR*nZze*q!Z$M~U6fkar)b*Qy^tY9x6H5Uy-n z68&OHLE;-cSJ=J6&vt8I)Px#;@Y*D&`A4}i{X|j@idlYQq-E80vECcc&waH33m7<{eNeb)< z09oLpNtqm$iHq81$fgcH>aC8-mdS|)X&Nf3IV@*#QDJ~9XdmVgQn}RxiXwyAYnkhw z_wH4SZ_%i76LL!BU6+-@l(6d!W)K4@D=1lvJ+>Qu@2d*_$ldbQuDGR&7HXv{*n5Qy zAdIf~L=2>m;=e67k^12wV9h?&F6aM`bb#*E)BoLH?CSpVWi+1M@1rafp0hz6AqowL z@j&@TAkDQ^#nod&hh%`2)>RYJJnKcFY+>E*R+G8vR3_|yz^7J(`JVv z!Z|ODJ?$1b@3aQzsfU20zQ1eGOUI zum;yY`Ixqq%kZ+yPeIT#;aS%&n=E&1CDZQNPpeK1^6UXt0d);UQAGU!Sy)}M>pVb| zc1}cgp<;^Dki&e3u`w;_tT}?;(*~0V3PqjPC($R|Vnv`fAB%;Oa%6qgwFivpkwZqz z@P$T=eSD9GV|bf~#Vw8<k zy|T3jQ5!qxQXnd&DYM2)d+M(v)f5Y4ctg4Hj%Bk^6lsZ;q{Q*UDTPkA!M>$xAC2+A z@!NVI0Yjf9rdPg2^8=FI&AcB%mG~s~0tNRN*#Abk^ZTOb&S}im2Sujx&+WJ)YyEvq zl$VW>Zv+JjB>M9i9GcJ(gtp1bpkf`n7T8L8e*HLZA6`C}%(C|5$E-}mV(v5McQs)F zuSY7M6e}pym4gXBIWuJ4DZ|!kYEoAEM}f=nJq; z2+o7QF}r(n==^5&?C^Yzr9(T7yvQt=>e3%)*vvCCHQ9T~0A>2@&Z^U+ZZD-4UD>^M zRYeM_bUvp}CO<`5Fa$asc|%Sb^CCBrZBj&4In^yJA);!fBFN7lq2+uo=7%7<{TvK- z|BIQKF9Hl#8+Za+Ba8<@QK`2Q32X6>a;i5uOGT99`x|18v(M5*6g?&Caki?Vm8AI$L2;x zs|*3y*jSZiFVJcWsGNpR} zQE)R)Aw+3+reA^bO}&)oFUBxc+5_zQ#U98rbnVEQ$R=IV9^2Yja$bR6J7AXH^#`9W z-jQi2UM=S;gT`Pmj@BxROb&Kurjqc}uG5|jWi8%h0{?l97?*aYh#u*RW7e)WcJu%p`;a=jTBE@Qykl%L!aak9U=aOEYzfgoXlSCebtsWuaKA_73IxM`FIEG z%=u9;&I%XWZsC1Hq=QfA22wh+Q(NSB0p-&2rHc{5V!W}!*`XJ1n$pMgO%vad`ZA;* zBkZZW9ceEFfG?Rpw7sO>ozSe;4F&Q?~pXzm9XoB~CVm zA+uHKhlxT$TaHq+p1(n}({!4=A~i|<#brur0;$2SU9$g>Pxr|ctj$k#ZxyIG_`f)b b8wmp{tdIMU=|1q&*b5-wNWGey4iWzY`(9H( literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/vpn-connecting-light.png b/artifacts/icon-family-v1/png/vpn-connecting-light.png new file mode 100644 index 0000000000000000000000000000000000000000..a656b58c1c571a7de7f56306e0d5aea2f6b4cc85 GIT binary patch literal 2922 zcmV-w3zhVVP)sCa52nZeUs1t_Yh7~<>hHy=wDpwt2V9k?-yJW*iDovlrg!vK>))g$A`{Q}DUtrN5ks09W%b|(5VhTGd))^9(XxwvH3 zG_kB-19Kg>0Ue00Q&{a6vwCOKhSoHE^@^(k1gfeAOJ_ky(HR(>flvvIa>4Z$HG0?X zt?Sn$Q@FT1JV)Z@K7?`?+CB)f5j9)H@-=Dy?x>sJ5XS-(m(Q9YahZ=;lTn?BPy~#2 zE3h8cs%723yD9RjlghzRO`W25f`na;>mcYJu=b*+H7*79d!uXjIdSAjfIz7BCeQ}~ zzmxjC5L02Ls(D~fv~jZ=4ud7Nm1?mVbRMY>=#n7@a!Y%3-5*k|n6dzqrq@g~K6c`M z=N}UE@tEJYeDCJS0hfIPa8Y^91%4yfgDwI_y6iq?#kqLbwuU{aR7&}d!B~1Z?sa|# z$lp}u8zTo>g$mD*4D^TfNW0YN2Aeh;5p#AKvmUXIpLe9umJcnaE?>IV#&}{>ty0L z{A|1lyr7m<-&IKC{z&9RmfG!=o;#YSfTzOYu>a7f%oNNOAag)V$?&bZ+X5))+k&)! zHW|y;)YVP1SEI~Si9{kXpt0x0`03%H1N~aAhH@3k!IXfE#YItE6+ncaw>7U{;-*h8 z>A7%T>3IPVEUQ_f%Dry2;bhpJ$3^l2cuZaZkI4(*F?j(zCNF@;GBCNa<08G3*P{YbufYT!j%01 zVr2Ol?_th(FI(jkB22I~`A9jlJN3Ju0{N%CRc(VyL|e)bAYUZ`IG``?f z`Cb@rXAq+a`o^Y?g8-~RsOC5}D;zC!)UN3IcO3Z5d5Wja9xeWu-Bo^~J=$;%r1sP1 zWFTfZnQneo;!xqhXP>|-=$>h3Q)C}0c0M>92`g-|vk77wWM9XqRNC1@)zNx3M*;}C z$=0Y;JMq~U5bQsjAlVZ@jc&9x3Nt5#s@+}y=Q)9rs!?FS?pQ2wwC{u?0d^OS+yNZ1 z^Qme%8fE4*mNg%nn-+z4cQr?LI&$kMm=!DHD7JGcYUu(;esh~E?F@p{!&wG#{wMf-}NeBw`YQY??$J-a}9x;u^%&i z(ly9h>(sYn0S;{3*a7^-wt%v5a%JT(r~Y$=qLS+2B7E1*F2a-PEW1tXiI~rdFH2w^ z(%seXwsidG0zOL?1B31Cg7s)R{?lIX8VJ=i0#!EVV+H<#i*{^Y^KQEBc)_Gl^+<#4 z#cuVyvaY?QA)HPd=|2+|{Y?UEVJz1DK-z71gh7^)VCw>t__HU4D=WT(p_)xyL9i?wRyAv}>m#M9y``Z72lGFl$Ca!IRclECvmo+FC=_zM2}ZV=JUKkb zs98>e3sim9U8LFh;F19CEs>Xj1Xs8Qj#Bub8*OES?g9FcKv9AstDWxRbvmx)1zB-! zgoIfE*9A&zzU@|fnIceHvp~>m6BOx0;aPgwPx(JKbi4@zcXY#UFct z#JfHoGpbj$wzhV;*|zJsp*x#4w2E+R;!+wakgk^kRaLel%xp1rYF%M}pIHe^Pgqd6 zWlu}PF1Opy*mhijvf3w6y(VEHWnKT+fXlaUU!8J3jT=m!93B)KU|uA_lP&;(C)%P7 zw(~*hkg@D&f5-dRfkqM*5^6jBC;m}XQawCVao91rvT|5#pjk~Xoe$a=`*-0PnRRZF z(GBT>GcG;X#Je~3a!(D==Euy<*1rCeN@kBUR(us`Z_g~=j2oS~ck6n)r+;aa(e(js zTh@Hwi*p&!Tb@ubhP5eJQfr%a;1uP--{cqbGjdNDrD{afIw;WR7BR0R06L&K8T|~ zibkV}ZfBEb>eRZzPXCDq5f&y<{D>vi>};LDl+^Z=9ay5NmB8b3-d9{0$^Ui!UqU0eY~C%WAF>Whs#CwDm{8 z&)O%9SjLJK@eIb6Hhn<=;N;XcvDn=zdNcMT+Y<^87xe4CuXW?b53?DcQ~Hbmr?{xR z<^rGclhaPwHo&uLnLBnjHQKJ=%tiW~0H^3VQ0_7SE6$6l9-x*dPo6w^@_5aE09c&% U;(2!I;s5{u07*qoM6N<$g1;@EM*si- literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/vpn-error-dark.png b/artifacts/icon-family-v1/png/vpn-error-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..c1b60ea1e12b3ecf4c9d471171b3b0e3298cacb8 GIT binary patch literal 3243 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 literal 0 HcmV?d00001 diff --git a/artifacts/icon-family-v1/png/vpn-error-light.png b/artifacts/icon-family-v1/png/vpn-error-light.png new file mode 100644 index 0000000000000000000000000000000000000000..644b18b53266fc70dbe27161e99a257a8be30694 GIT binary patch literal 3307 zcmV