#!/bin/sh set -eu APP_NAME="lemana-vpn" DEFAULT_RAW_BASE_URL="https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main" RAW_BASE_URL="${LEMANA_VPN_RAW_BASE_URL:-$DEFAULT_RAW_BASE_URL}" INSTALL_BIN_DIR="${LEMANA_VPN_BIN_DIR:-$HOME/bin}" 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" USERNAME="${LEMANA_VPN_USERNAME:-60103293}" BW_ITEM="${LEMANA_VPN_BW_ITEM:-LM LDAP}" USE_BITWARDEN=1 USE_TOUCHID=1 INSTALL_SUDOERS=1 INSTALL_ALIASES=1 CONFIGURE_KEYCHAIN=0 DRY_RUN=0 FORCE=0 usage() { cat <<'USAGE' Usage: sh install.sh [options] Options: --with-bitwarden Install/use Bitwarden CLI module (default) --without-bitwarden Do not install/use Bitwarden CLI; use Keychain credentials --with-touchid Install/use keychain-fingerprint Touch ID helper (default) --without-touchid Do not install/use Touch ID helper --configure-keychain Prompt for LDAP password and TOTP secret after install --username VALUE Corporate LDAP username (default: 60103293) --bw-item VALUE Bitwarden item name (default: LM LDAP) --raw-base-url URL Raw file base URL for curl installs --no-sudoers Do not install sudoers rules --no-shell Do not update ~/.zshrc aliases --minimal Same as --without-bitwarden --without-touchid --dry-run Print actions without changing files --force Reinstall files even when present -h, --help Show this help Examples: sh install.sh sh install.sh --minimal --configure-keychain sh install.sh --without-touchid USAGE } while [ "$#" -gt 0 ]; do case "$1" in --with-bitwarden) USE_BITWARDEN=1 ;; --without-bitwarden) USE_BITWARDEN=0 ;; --with-touchid) USE_TOUCHID=1 ;; --without-touchid) USE_TOUCHID=0 ;; --configure-keychain) CONFIGURE_KEYCHAIN=1 ;; --username) shift [ "$#" -gt 0 ] || { echo "--username requires a value" >&2; exit 1; } USERNAME="$1" ;; --bw-item) shift [ "$#" -gt 0 ] || { echo "--bw-item requires a value" >&2; exit 1; } BW_ITEM="$1" ;; --raw-base-url) shift [ "$#" -gt 0 ] || { echo "--raw-base-url requires a value" >&2; exit 1; } RAW_BASE_URL="${1%/}" ;; --no-sudoers) INSTALL_SUDOERS=0 ;; --no-shell) INSTALL_ALIASES=0 ;; --minimal) USE_BITWARDEN=0 USE_TOUCHID=0 ;; --dry-run) DRY_RUN=1 ;; --force) FORCE=1 ;; -h|--help) usage exit 0 ;; *) echo "Unknown option: $1" >&2 usage >&2 exit 1 ;; esac shift done log() { printf '%s\n' "$*" } die() { printf 'ERROR: %s\n' "$*" >&2 exit 1 } run() { if [ "$DRY_RUN" -eq 1 ]; then printf '+' for arg in "$@"; do printf ' %s' "$arg" done printf '\n' return 0 fi "$@" } need_cmd() { command -v "$1" >/dev/null 2>&1 || die "Command not found: $1" } script_dir() { case "$0" in */*) cd "$(dirname "$0")" 2>/dev/null && pwd ;; *) pwd ;; esac } download_file() { src="$1" dst="$2" local_dir="$(script_dir)" if [ -f "$local_dir/$src" ]; then run cp "$local_dir/$src" "$dst" return 0 fi if [ -f "$PWD/$src" ]; then run cp "$PWD/$src" "$dst" return 0 fi need_cmd curl run curl -fsSL "$RAW_BASE_URL/$src" -o "$dst" } write_file() { dst="$1" content="$2" if [ "$DRY_RUN" -eq 1 ]; then printf '+ write %s\n' "$dst" return 0 fi printf '%s\n' "$content" > "$dst" } install_homebrew_packages() { need_cmd brew for pkg in openconnect pipx; do if brew list "$pkg" >/dev/null 2>&1; then log "Homebrew package already installed: $pkg" else log "Installing Homebrew package: $pkg" run brew install "$pkg" fi done if [ "$USE_BITWARDEN" -eq 1 ]; then if brew list bitwarden-cli >/dev/null 2>&1; then log "Homebrew package already installed: bitwarden-cli" else log "Installing Homebrew package: bitwarden-cli" run brew install bitwarden-cli fi fi } install_openconnect_lite() { need_cmd pipx if [ -x "$HOME/.local/bin/openconnect-lite" ] && [ "$FORCE" -eq 0 ]; then log "openconnect-lite already installed" else log "Installing openconnect-lite via pipx" run pipx install openconnect-lite fi if pipx --help 2>/dev/null | grep -q ' pin '; then run pipx pin openconnect-lite >/dev/null 2>&1 || true fi } install_cli() { tmp="$1" run mkdir -p "$INSTALL_BIN_DIR" download_file "bin/vpn-lemanapro.sh" "$tmp/vpn-lemanapro.sh" run install -m 755 "$tmp/vpn-lemanapro.sh" "$INSTALL_BIN_DIR/vpn-lemanapro.sh" download_file "uninstall.sh" "$tmp/uninstall.sh" run install -m 755 "$tmp/uninstall.sh" "$INSTALL_BIN_DIR/uninstall-lemana-vpn.sh" } install_config() { tmp="$1" run mkdir -p "$CONFIG_DIR" "$OC_CONFIG_DIR" download_file "templates/openconnect-lite-config.toml" "$tmp/openconnect-lite-config.toml" 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" fi env_content="LEMANA_VPN_USERNAME=\"$USERNAME\" 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" run install -m 600 "$tmp/env" "$CONFIG_DIR/env" } install_dns_cleanup() { tmp="$1" dns_cleanup_dir="$(dirname "$DNS_CLEANUP")" download_file "libexec/lemana-vpn-dns-cleanup" "$tmp/lemana-vpn-dns-cleanup" run sudo install -d -m 755 -o root -g wheel "$dns_cleanup_dir" log "Installing DNS cleanup wrapper: $DNS_CLEANUP" run sudo install -m 755 -o root -g wheel "$tmp/lemana-vpn-dns-cleanup" "$DNS_CLEANUP" } install_sudoers() { [ "$INSTALL_SUDOERS" -eq 1 ] || return 0 openconnect_bin="$(brew --prefix)/bin/openconnect" [ -x "$openconnect_bin" ] || openconnect_bin="$(command -v openconnect || true)" [ -n "$openconnect_bin" ] || die "openconnect binary not found" tmp="$1" current_user="$(id -un)" run sudo install -d -m 755 -o root -g wheel /etc/sudoers.d write_file "$tmp/sudoers-openconnect" "$current_user ALL=(ALL) NOPASSWD: $openconnect_bin" run sudo install -m 440 -o root -g wheel "$tmp/sudoers-openconnect" /etc/sudoers.d/lemana-vpn-openconnect run sudo visudo -c -f /etc/sudoers.d/lemana-vpn-openconnect write_file "$tmp/sudoers-dns" "$current_user ALL=(ALL) NOPASSWD: $DNS_CLEANUP" run sudo install -m 440 -o root -g wheel "$tmp/sudoers-dns" /etc/sudoers.d/lemana-vpn-dns run sudo visudo -c -f /etc/sudoers.d/lemana-vpn-dns } install_touchid_helper() { [ "$USE_TOUCHID" -eq 1 ] || return 0 if [ -x "$INSTALL_BIN_DIR/keychain-fingerprint" ] && [ "$FORCE" -eq 0 ]; then log "Touch ID helper already installed: $INSTALL_BIN_DIR/keychain-fingerprint" return 0 fi need_cmd git need_cmd swiftc tmp="$1" log "Building keychain-fingerprint helper" run git clone --depth 1 https://github.com/dss99911/keychain-fingerprint.git "$tmp/keychain-fingerprint" run swiftc -o "$tmp/keychain-fingerprint-bin" "$tmp/keychain-fingerprint/main.swift" -framework LocalAuthentication -framework Security run install -m 700 "$tmp/keychain-fingerprint-bin" "$INSTALL_BIN_DIR/keychain-fingerprint" } install_shell_aliases() { [ "$INSTALL_ALIASES" -eq 1 ] || return 0 zshrc="$HOME/.zshrc" tmp="$1" [ -f "$zshrc" ] || run touch "$zshrc" block="$tmp/zshrc-block" if [ "$DRY_RUN" -eq 1 ]; then printf '+ update %s aliases\n' "$zshrc" return 0 fi cat > "$block" <>> lemana-vpn vpn() { "$INSTALL_BIN_DIR/vpn-lemanapro.sh" "\$@"; } vpn-debug() { "$INSTALL_BIN_DIR/vpn-lemanapro.sh" --debug "\$@"; } vpn-fix-dns() { sudo "$DNS_CLEANUP"; } # <<< lemana-vpn EOF awk ' /^# >>> lemana-vpn$/ { skip=1; next } /^# <<< lemana-vpn$/ { skip=0; next } skip != 1 { print } ' "$zshrc" > "$tmp/zshrc" { cat "$tmp/zshrc" printf '\n' cat "$block" } > "$tmp/zshrc.new" mv "$tmp/zshrc.new" "$zshrc" } maybe_login_bitwarden() { [ "$USE_BITWARDEN" -eq 1 ] || return 0 command -v bw >/dev/null 2>&1 || return 0 status="$(bw status 2>/dev/null || true)" if printf '%s\n' "$status" | grep -q '"status":"unauthenticated"'; then log "Bitwarden CLI is not logged in. Run later: bw login" elif printf '%s\n' "$status" | grep -q '"status":"locked"'; then log "Bitwarden CLI is logged in but locked. First vpn run will ask for master password." else log "Bitwarden CLI is available." fi } main() { [ "$(uname -s)" = "Darwin" ] || die "This installer supports macOS only" tmp="$(mktemp -d)" trap 'rm -rf "$tmp"' EXIT INT TERM log "Installing Lemana VPN" log "Modules: bitwarden=$USE_BITWARDEN touchid=$USE_TOUCHID sudoers=$INSTALL_SUDOERS shell=$INSTALL_ALIASES" install_homebrew_packages install_openconnect_lite install_cli "$tmp" install_config "$tmp" install_dns_cleanup "$tmp" install_sudoers "$tmp" install_touchid_helper "$tmp" install_shell_aliases "$tmp" maybe_login_bitwarden if [ "$CONFIGURE_KEYCHAIN" -eq 1 ]; then run "$INSTALL_BIN_DIR/vpn-lemanapro.sh" --configure-keychain fi log "" log "Done." log "Open a new shell or run: exec zsh" log "Connect: vpn" log "Status: vpn --status" } main "$@"