Make installer interactive for credential source selection

This commit is contained in:
2026-05-26 14:05:36 +03:00
parent 7c625e840e
commit a52b4ecdd4
10 changed files with 1634 additions and 45 deletions

View File

@@ -11,6 +11,7 @@ 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}"
CREDENTIAL_SOURCE="${LEMANA_VPN_CREDENTIAL_SOURCE:-bitwarden}"
USE_BITWARDEN=1
USE_TOUCHID=1
INSTALL_SUDOERS=1
@@ -22,6 +23,7 @@ DRY_RUN=0
FORCE=0
INTERACTIVE=auto
BITWARDEN_FORCED=0
CREDENTIAL_SOURCE_FORCED=0
TOUCHID_FORCED=0
SUDOERS_FORCED=0
SHELL_FORCED=0
@@ -75,6 +77,7 @@ Usage:
Options:
--with-bitwarden Install/use Bitwarden CLI module (default)
--without-bitwarden Do not install/use Bitwarden CLI; use Keychain credentials
--credential-source VALUE Credential source: bitwarden or keychain
--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
@@ -97,6 +100,7 @@ Options:
Examples:
sh install.sh
sh install.sh --minimal --configure-keychain
sh install.sh --credential-source keychain --configure-keychain
sh install.sh --without-touchid
USAGE
}
@@ -104,12 +108,36 @@ USAGE
while [ "$#" -gt 0 ]; do
case "$1" in
--with-bitwarden)
CREDENTIAL_SOURCE="bitwarden"
USE_BITWARDEN=1
BITWARDEN_FORCED=1
CREDENTIAL_SOURCE_FORCED=1
;;
--without-bitwarden)
CREDENTIAL_SOURCE="keychain"
USE_BITWARDEN=0
USE_TOUCHID=0
BITWARDEN_FORCED=1
CREDENTIAL_SOURCE_FORCED=1
;;
--credential-source)
shift
[ "$#" -gt 0 ] || { echo "--credential-source requires bitwarden or keychain" >&2; exit 1; }
CREDENTIAL_SOURCE="$1"
CREDENTIAL_SOURCE_FORCED=1
case "$CREDENTIAL_SOURCE" in
bitwarden)
USE_BITWARDEN=1
;;
keychain)
USE_BITWARDEN=0
USE_TOUCHID=0
;;
*)
echo "--credential-source requires bitwarden or keychain" >&2
exit 1
;;
esac
;;
--with-touchid)
USE_TOUCHID=1
@@ -167,9 +195,11 @@ while [ "$#" -gt 0 ]; do
--interactive) INTERACTIVE=1 ;;
--non-interactive) INTERACTIVE=0 ;;
--minimal)
CREDENTIAL_SOURCE="keychain"
USE_BITWARDEN=0
USE_TOUCHID=0
BITWARDEN_FORCED=1
CREDENTIAL_SOURCE_FORCED=1
TOUCHID_FORCED=1
;;
--dry-run) DRY_RUN=1 ;;
@@ -243,7 +273,7 @@ need_cmd() {
}
has_tty() {
[ -r /dev/tty ] && [ -w /dev/tty ]
{ [ -r /dev/tty ] && [ -w /dev/tty ]; } || [ -t 0 ]
}
interactive_enabled() {
@@ -255,6 +285,22 @@ interactive_enabled() {
esac
}
prompt_printf() {
if [ -w /dev/tty ]; then
printf "$@" > /dev/tty
else
printf "$@"
fi
}
prompt_read_answer() {
if [ -r /dev/tty ]; then
IFS= read -r answer < /dev/tty || answer=""
else
IFS= read -r answer || answer=""
fi
}
yes_no() {
prompt="$1"
default_answer="$2"
@@ -272,17 +318,69 @@ yes_no() {
fi
while :; do
printf '%s%s %s%s ' "$C_BOLD" "$prompt" "$suffix" "$C_RESET" > /dev/tty
IFS= read -r answer < /dev/tty || answer=""
prompt_printf '%s%s %s%s ' "$C_BOLD" "$prompt" "$suffix" "$C_RESET"
prompt_read_answer
case "$answer" in
"") [ "$default_answer" = "y" ]; return $? ;;
y|Y|yes|YES|Yes|д|Д|да|Да|ДА) return 0 ;;
n|N|no|NO|No|н|Н|нет|Нет|НЕТ) return 1 ;;
*) printf 'Введите y или n.\n' > /dev/tty ;;
*) prompt_printf 'Введите y или n.\n' ;;
esac
done
}
choose_credential_source_interactive() {
log_step "Настраиваю способ хранения credentials"
log_detail "Можно выбрать Bitwarden или бесплатный macOS Keychain flow с ручным вводом LDAP password и TOTP seed."
while :; do
prompt_printf '\n'
prompt_printf '%sКак хранить VPN credentials?%s\n' "$C_BOLD" "$C_RESET"
prompt_printf ' 1) Bitwarden -> macOS Keychain\n'
prompt_printf ' 2) macOS Keychain: ввести LDAP password и TOTP seed сейчас\n'
prompt_printf ' 3) macOS Keychain: настрою вручную позже\n'
prompt_printf '%sВыбор [1/2/3, Enter=1]:%s ' "$C_BOLD" "$C_RESET"
prompt_read_answer
case "$answer" in
""|1)
CREDENTIAL_SOURCE=bitwarden
USE_BITWARDEN=1
;;
2)
CREDENTIAL_SOURCE=keychain
USE_BITWARDEN=0
USE_TOUCHID=0
CONFIGURE_KEYCHAIN=1
;;
3)
CREDENTIAL_SOURCE=keychain
USE_BITWARDEN=0
USE_TOUCHID=0
CONFIGURE_KEYCHAIN=0
;;
*)
prompt_printf 'Введите 1, 2 или 3.\n'
continue
;;
esac
break
done
case "$CREDENTIAL_SOURCE" in
bitwarden)
log_info "Credential source: Bitwarden sync into macOS Keychain"
;;
keychain)
if [ "$CONFIGURE_KEYCHAIN" -eq 1 ]; then
log_info "Credential source: macOS Keychain, credentials будут запрошены после установки"
else
log_info "Credential source: macOS Keychain, credentials можно настроить позже через vpn --configure-keychain"
fi
;;
esac
}
bool_word() {
if "$@" >/dev/null 2>&1; then
printf 'yes'
@@ -321,19 +419,39 @@ print_detected_state() {
choose_modules() {
print_detected_state
case "$CREDENTIAL_SOURCE" in
bitwarden)
USE_BITWARDEN=1
;;
keychain)
USE_BITWARDEN=0
USE_TOUCHID=0
;;
*)
die "Unknown credential source: $CREDENTIAL_SOURCE"
;;
esac
if ! interactive_enabled; then
log_skip "Interactive prompts: off"
return 0
fi
log_info "Interactive prompts: on"
log_detail "Будут вопросы только по отсутствующим опциональным модулям; флаги командной строки имеют приоритет."
log_detail "Установщик проведёт по выбору credential source и отсутствующих опциональных модулей; флаги командной строки имеют приоритет."
if [ "$BITWARDEN_FORCED" -eq 0 ] && ! command -v bw >/dev/null 2>&1; then
if [ "$CREDENTIAL_SOURCE_FORCED" -eq 0 ]; then
choose_credential_source_interactive
fi
if [ "$CREDENTIAL_SOURCE" = "bitwarden" ] && [ "$BITWARDEN_FORCED" -eq 0 ] && ! command -v bw >/dev/null 2>&1; then
if yes_no "Bitwarden CLI не найден. Поставить модуль Bitwarden?" y; then
CREDENTIAL_SOURCE=bitwarden
USE_BITWARDEN=1
else
CREDENTIAL_SOURCE=keychain
USE_BITWARDEN=0
USE_TOUCHID=0
fi
fi
@@ -386,7 +504,7 @@ choose_modules() {
fi
fi
if [ "$CONFIGURE_KEYCHAIN_FORCED" -eq 0 ] && [ "$USE_BITWARDEN" -eq 0 ]; then
if [ "$CONFIGURE_KEYCHAIN_FORCED" -eq 0 ] && [ "$CREDENTIAL_SOURCE" = "keychain" ] && [ "$CONFIGURE_KEYCHAIN" -eq 0 ]; then
if ! keychain_has openconnect-lite "$USERNAME" || ! keychain_has openconnect-lite "totp/$USERNAME"; then
if yes_no "Bitwarden отключён, а Keychain credentials неполные. Записать LDAP-пароль и TOTP seed после установки?" y; then
CONFIGURE_KEYCHAIN=1
@@ -510,6 +628,7 @@ install_config() {
fi
env_content="LEMANA_VPN_USERNAME=\"$USERNAME\"
LEMANA_VPN_CREDENTIAL_SOURCE=\"$CREDENTIAL_SOURCE\"
LEMANA_VPN_BW_ITEM=\"$BW_ITEM\"
LEMANA_VPN_USE_BITWARDEN=\"$USE_BITWARDEN\"
LEMANA_VPN_USE_TOUCHID=\"$USE_TOUCHID\"
@@ -757,8 +876,8 @@ EOF
}
maybe_login_bitwarden() {
if [ "$USE_BITWARDEN" -ne 1 ]; then
log_skip "Bitwarden module disabled; credentials будут браться из macOS Keychain."
if [ "$CREDENTIAL_SOURCE" != "bitwarden" ]; then
log_skip "Credential source is keychain; пропускаю Bitwarden login."
return 0
fi
if ! command -v bw >/dev/null 2>&1; then
@@ -789,7 +908,7 @@ main() {
log_step "Начинаю установку Lemana VPN"
log_detail "Повторный запуск безопасен: файлы обновляются идемпотентно, существующие credentials не перезаписываются."
log_info "Modules: bitwarden=$USE_BITWARDEN touchid=$USE_TOUCHID sudoers=$INSTALL_SUDOERS shell=$INSTALL_ALIASES app=$INSTALL_APP autostart=$INSTALL_AUTOSTART"
log_info "Modules: credential_source=$CREDENTIAL_SOURCE bitwarden=$USE_BITWARDEN touchid=$USE_TOUCHID sudoers=$INSTALL_SUDOERS shell=$INSTALL_ALIASES app=$INSTALL_APP autostart=$INSTALL_AUTOSTART"
install_homebrew_packages
install_openconnect_lite