#!/bin/bash

# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at 
# https://securityonion.net/license; you may not use this file except in compliance with the
# Elastic License 2.0.


whiptail_airgap() {

	[ -n "$TESTING" ] && return

	local node_str='node'
	[[ $is_manager || $is_import ]] && node_str='manager'

	INTERWEBS=$(whiptail --title "$whiptail_title" --menu \
	"How should this $node_str be installed?\n\nFor more information, please see:\n$DOC_BASE_URL/airgap.html" 13 70 2 \
	"Standard    " "This $node_str has access to the Internet"  \
	"Airgap      " "This $node_str does not have access to the Internet" 3>&1 1>&2 2>&3 )

	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus

	INTERWEBS=$(echo "${INTERWEBS^^}" | tr -d ' ')
	if [[ "$INTERWEBS" == 'AIRGAP' ]]; then
		is_airgap=true
	fi
}

whiptail_debian_reboot_required() {

	[ -n "$TESTING" ] && return

	read -r -d '' message <<- EOM

	Packages were upgraded and a reboot is required prior to Security Onion installation.

	Once the reboot has completed, rerun Security Onion setup.

	Press TAB and then the ENTER key to reboot the system.

	EOM

	whiptail --title "$whiptail_title" --msgbox "$message" 24 75 --scrolltext
}

whiptail_desktop_install() {

	[ -n "$TESTING" ] && return

	read -r -d '' message <<- EOM
	
	Welcome to the Security Onion Desktop install!

	Would you like to join this desktop to an existing grid?

	EOM
	whiptail --title "$whiptail_title" \
		--yesno "$message" 11 75 --defaultno

	if [ $? -eq 0 ]; then
		is_desktop_grid=true
	else
		is_desktop_grid=false
	fi

}

whiptail_desktop_nongrid_iso() {

	[ -n "$TESTING" ] && return

	read -r -d '' message <<- EOM
	
	You have selected this Security Onion Desktop to be independent.

	Would you still like to have the graphical interface loaded at boot?

	NOTE: Selecting no will exit without making changes.

	EOM
	whiptail --title "$whiptail_title" \
		--yesno "$message" 11 75 --defaultno

}

whiptail_desktop_nongrid_network() {

	[ -n "$TESTING" ] && return

	read -r -d '' message <<- EOM
	
	You have selected this Security Onion Desktop to be independent.

	Would you still like to install and load the graphical interface?

	NOTE: Selecting no will exit without making changes.

	EOM
	whiptail --title "$whiptail_title" \
		--yesno "$message" 11 75 --defaultno

}

whiptail_avoid_default_hostname() {
	[ -n "$TESTING" ] && return

	read -r -d '' message <<- EOM
	To prevent hostname conflicts, avoid using the default 'securityonion' hostname in a distributed environment.

	You can choose to use this default hostname anyway, or change it to a new hostname.
	EOM

	whiptail --title "$whiptail_title" \
		--yesno "$message" 11 75 \
		--yes-button "Use Anyway" --no-button "Change" --defaultno
}

whiptail_bond_nics_mtu() {

	[ -n "$TESTING" ] && return

	# Set the MTU on the monitor interface
	MTU=$(whiptail --title "$whiptail_title" --inputbox \
	"Enter the MTU for the monitor NICs:" 10 75 "$1" 3>&1 1>&2 2>&3)

	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus
}

whiptail_cancel() {
	[ -z "$TESTING" ] && whiptail --title "$whiptail_title" --msgbox "Cancelling Setup." 8 75
	
	if [ -d "/root/installtmp" ]; then
		{
			echo "/root/installtmp exists";
			install_cleanup;
			echo "/root/installtmp removed";
		} >> $setup_log 2>&1
	fi

	title "User cancelled setup."
	
	exit 1
}

whiptail_accept_telemetry() {

	[ -n "$TESTING" ] && return

	read -r -d '' message <<- EOM

	The Security Onion development team could use your help! Enabling SOC
	Telemetry will help the team understand which UI features are being
	used and enables informed prioritization of future development.

	Adjust this setting at anytime via the SOC Configuration screen.

	Documentation: https://docs.securityonion.net/en/2.4/telemetry.html

	Enable SOC Telemetry to help improve future releases?
	EOM
	whiptail --title "$whiptail_title" --yesno "$message" 15 75
	telemetry=$?
}

whiptail_check_exitstatus() {
	case $1 in
		1)
			whiptail_cancel
			;;
		255)
			whiptail --title "$whiptail_title" --msgbox "Whiptail error occured, exiting. Check log for details." 8 75
			exit
			;;
	esac
}

whiptail_create_admin_user() {

	[ -n "$TESTING" ] && return

	ADMINUSER=$(whiptail --title "$whiptail_title" --inputbox \
	"Please enter a username for a new system admin user: \nThe local onion account will be disabled during this install" 10 60 "$1" 3>&1 1>&2 2>&3)

	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus
}

whiptail_create_admin_user_password1() {

	[ -n "$TESTING" ] && return

	ADMINPASS1=$(whiptail --title "$whiptail_title" --passwordbox \
	"Enter a password for $ADMINUSER:" 10 60 3>&1 1>&2 2>&3)

	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus
}

whiptail_create_admin_user_password2() {

	[ -n "$TESTING" ] && return

	ADMINPASS2=$(whiptail --title "$whiptail_title" --passwordbox \
	"Re-enter a password for $ADMINUSER:" 10 60 3>&1 1>&2 2>&3)

	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus

}

whiptail_create_web_user() {

	[ -n "$TESTING" ] && return

	WEBUSER=$(whiptail --title "$whiptail_title" --inputbox \
	"Please enter an email address to create an administrator account for the Security Onion Console (SOC) web interface.\n\nThis will also be used for Elasticsearch and Kibana.\n\nMust only include letters, numbers, or + - _ % . @ characters. All capitalized letters will be converted to lowercase." 15 60 "$1" 3>&1 1>&2 2>&3)

	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus

	WEBUSER=${WEBUSER,,}
}

whiptail_create_web_user_password1() {

	[ -n "$TESTING" ] && return

	WEBPASSWD1=$(whiptail --title "$whiptail_title" --passwordbox \
	"Enter a password for $WEBUSER:" 10 60 3>&1 1>&2 2>&3)

	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus
}

whiptail_create_web_user_password2() {

	[ -n "$TESTING" ] && return

	WEBPASSWD2=$(whiptail --title "$whiptail_title" --passwordbox \
	"Re-enter a password for $WEBUSER:" 10 60 3>&1 1>&2 2>&3)

	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus

}

whiptail_requirements_error() {

	local requirement_needed=$1
	local current_val=$2
	local needed_val=$3

	[ -n "$TESTING" ] && return

	if [[ $(echo "$requirement_needed" | tr '[:upper:]' '[:lower:]') =~ 'nic' ]]; then
		whiptail --title "$whiptail_title" \
			--msgbox "This machine currently has $current_val $requirement_needed, but needs $needed_val to meet minimum requirements. Select OK to exit setup and reconfigure the machine."  10 75
		
		# Same as whiptail_cancel, but changed the wording to exit instead of cancel.
		whiptail --title "$whiptail_title" --msgbox "Exiting Setup. No changes have been made." 8 75
		if [ -d "/root/installtmp" ]; then
			{
				echo "/root/installtmp exists";
				install_cleanup;
				echo "/root/installtmp removed";
			} >> $setup_log 2>&1
		fi
		exit
	else
		whiptail --title "$whiptail_title" \
			--yesno "This machine currently has $current_val $requirement_needed, but needs $needed_val to meet minimum requirements. Select YES to continue anyway, or select NO to cancel."  10 75

		local exitstatus=$?
		whiptail_check_exitstatus $exitstatus
	fi
}

whiptail_storage_requirements() {
	local mount=$1
	local current_val=$2
	local needed_val=$3

	[ -n "$TESTING" ] && return

	read -r -d '' message <<- EOM
		Free space on mount point '${mount}' is currently ${current_val}.

		You need ${needed_val} to meet minimum requirements.

		Visit $DOC_BASE_URL/hardware.html for more information.

		Select YES to continue anyway, or select NO to cancel.
	EOM

	whiptail \
		--title "$whiptail_title" \
		--yesno "$message" \
		14 75

	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus
}

whiptail_dhcp_or_static() {

	[ -n "$TESTING" ] && return

	address_type=$(whiptail --title "$whiptail_title" --menu \
	"Choose how to set up your management interface. We recommend using a static IP address." 20 78 4 \
	"STATIC" "Set a static IPv4 address (recommended)" \
	"DHCP" "Use DHCP to configure the management interface" 3>&1 1>&2 2>&3 )
	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus

	if [[ $address_type == "DHCP" ]]; then
		whiptail_dhcp_warn
	fi

	export address_type

}

whiptail_dhcp_warn() {
	[ -n "$TESTING" ] && return

	if [[ $setup_type == "iso" ]]; then
		local interaction_text="Select YES to keep DHCP or NO to go back."
		local window_type="yesno"
	else
		local interaction_text="Press the Enter key to continue."
		local window_type="msgbox"
	fi

	read -r -d '' dhcp_message <<- EOM
		WARNING: Using DHCP can cause problems if your IP address changes. If you want to use DHCP, make sure that you have a DHCP reservation so that this does not occur. Otherwise, use a static IP address to be safe. 

		$interaction_text
	EOM

	whiptail \
	--title "$whiptail_title" \
	--"$window_type" "$dhcp_message" \
	14 75

	local exitstatus=$?
	if [[ $setup_type == "iso" ]]; then
		case $exitstatus in
			1)
				whiptail_dhcp_or_static
				;;
			255)
				whiptail --title "$whiptail_title" --msgbox "Whiptail error occured, exiting. Check log for details." 8 75
				exit
				;;
		esac
	else
		whiptail_check_exitstatus $exitstatus
	fi
	
}

whiptail_dockernet_check(){

	[ -n "$TESTING" ] && return

	whiptail --title "$whiptail_title" --yesno \
	"Do you want to keep the default Docker IP range?\n\nIf you are unsure, please accept the default option of Yes." 10 75

}

whiptail_dockernet_sosnet() {

	[ -n "$TESTING" ] && return

	DOCKERNET=$(whiptail --title "$whiptail_title" --inputbox \
	"\nEnter a /24 size network range for SOS containers to use WITHOUT the /24 suffix. This range will be used on ALL nodes. Any range within 172.17.0.0/24 cannot be used." 11 65 "$1" 3>&1 1>&2 2>&3)

	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus

}

whiptail_end_settings() {
	[ -n "$TESTING" ] && return

	# BASIC INFO (NETWORK, HOSTNAME, DESCRIPTION, ETC)

	read -r -d '' end_msg <<- EOM
	Security Onion Version: $SOVERSION
	Node Type: $install_type
	Hostname: $HOSTNAME
	EOM
	[[ -n $NODE_DESCRIPTION ]] && __append_end_msg "Description: $NODE_DESCRIPTION"

	[[ $is_airgap ]] && __append_end_msg "Airgap: True"

	if [[ $is_minion ]]; then 
		__append_end_msg "Manager Hostname: $MSRV"
		__append_end_msg "Manager IP: $MSRVIP"
	fi

	[[ $is_iso ]] && __append_end_msg "Network: $address_type"

	__append_end_msg "Management NIC: $MNIC"
	__append_end_msg "Management IP: $MAINIP"

	if [[ $address_type == 'STATIC' ]]; then
		__append_end_msg "Gateway: $MGATEWAY"
		__append_end_msg "DNS: $MDNS"
		__append_end_msg "DNS Domain: $MSEARCH"
	fi

	if [[ -n $so_proxy ]]; then
		__append_end_msg "Proxy:"
		__append_end_msg "  Server URL: $proxy_addr"
		[[ -n $proxy_user ]] && __append_end_msg "  User: $proxy_user"
	else
		__append_end_msg "Proxy: N/A"
	fi

	if [[ $is_sensor ]]; then
		__append_end_msg "Bond NIC(s):"
		for nic in "${BNICS[@]}"; do
			__append_end_msg "  - $nic"
		done
		[[ -n $MTU ]] && __append_end_msg "MTU: $MTU"
	fi

	local homenet_arr
	if [[ -n $HNMANAGER ]]; then
		__append_end_msg "Home Network(s):"
		IFS="," read -r -a homenet_arr <<< "$HNMANAGER"
		for net in "${homenet_arr[@]}"; do
			__append_end_msg "  - $net"
		done
	fi

	[[ -n $REDIRECTIT ]] && __append_end_msg "Access URL: https://${REDIRECTIT}"

	[[ -n $ALLOW_CIDR ]] && __append_end_msg "Allowed IP or Subnet: $ALLOW_CIDR"

	[[ -n $WEBUSER ]] && __append_end_msg "Web User: $WEBUSER"

	[[ -n $DOCKERNET ]] && __append_end_msg "Docker network: $DOCKERNET/24"
	if [[ ${#ntp_servers[@]} -gt 0 ]]; then
		__append_end_msg "NTP Servers:"
		for server in "${ntp_servers[@]}"; do
			__append_end_msg "  - $server"
		done
	fi

	if [[ ! $is_airgap ]] && [[ $waitforstate ]]; then
		if [[ $telemetry -eq 0 ]]; then
			__append_end_msg "SOC Telemetry: enabled"
		else
			__append_end_msg "SOC Telemetry: disabled"
		fi
	fi

	# ADVANCED
	if [[ $MANAGERADV == 'ADVANCED' ]]; then
		__append_end_msg "Advanced Manager Settings:"
		[[ -n $ESCLUSTERNAME ]] && __append_end_msg "  ES Cluster Name: $ESCLUSTERNAME"
		if [[ ${#BLOGS[@]} -gt 0 ]]; then
			__append_end_msg "  Zeek Logs Enabled:"
			for log in "${BLOGS[@]}"; do
				__append_end_msg "    - $log"
			done
		fi
	fi

	local msg
	read -r -d '' msg <<-EOM
	$end_msg

	Press the TAB key to select yes or no.
	EOM

	whiptail --title "The following options have been set, would you like to proceed?" --yesno "$msg" 24 75 --scrolltext

	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus

	echo "$end_msg" > /root/install_summary
	printf '%s\n' 'Install summary:' "$end_msg" >> "$setup_log"
}

__append_end_msg() {
	local newline=$1

	read -r -d '' end_msg <<- EOM
	$end_msg
	$newline
	EOM
}

whiptail_focal_warning() {

	[ -n "$TESTING" ] && return

	read -r -d '' focal_warning_continue <<- EOM

	WARNING: Ubuntu 20.04 is only supported as a minion role.

	This node may not install or operate as expected if installed
	as a manager, managersearch, standalone, eval, or import.

	Would you like to continue the install?

	EOM
	whiptail --title "$whiptail_title" \
		--yesno "$focal_warning_continue" 14 75 --defaultno

	local exitstatus=$?
	return $exitstatus

}

whiptail_gauge_post_setup() {

	if [ -n "$TESTING" ]; then
		cat >> $setup_log 2>&1
	else
		local msg=$1

		whiptail --title "$whiptail_title" --gauge "$msg" 6 60 96
	fi
}

 whiptail_idh_preferences() {

	[ -n "$TESTING" ] && return

	idh_preferences=$(whiptail --title "$whiptail_title" --radiolist \
		"\nBy default, IDH services will be bound to all interfaces and IP addresses on this system.\n\nIf you would like to prevent IDH services from being published on this system's management IP, you can select the option below." 20 75 5 \
		"$MAINIP" "Disable IDH services on this management IP " OFF 3>&1 1>&2 2>&3 )

	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus
}

whiptail_idh_services() {

	[ -n "$TESTING" ] && return

	IDH_SERVICES=$(whiptail --title "$whiptail_title" --radiolist \
		"\nThe IDH node can mimic many different services.\n\nChoose one of the common options along with their default ports (TCP) or select the Custom option to build a customized set of services." 20 75 5 \
		"Linux Webserver (NAS Skin)" "Apache (80), FTP (21), SSH (22)" ON \
		"MySQL Server" "MySQL (3306), SSH (22)" OFF \
		"MSSQL Server" "Microsoft SQL (1433), VNC (5900)" OFF \
		"Custom" "Select a custom set of services" OFF 3>&1 1>&2 2>&3 )

	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus
}


whiptail_idh_services_custom() {

	[ -n "$TESTING" ] && return

	IDH_SERVICES=$(whiptail --title "$whiptail_title" --checklist \
		"\nThe IDH node can mimic many different services.\n\nChoose one or more of the following services along with their default ports. Some services have additional configuration options, please consult the documentation for further information." 25 75 8 \
		"FTP" "  TCP/21,   Additional Configuration Available   " OFF \
		"Git" "  TCP/9418                                       " OFF \
		"HTTP" "  TCP/80,   Additional Configuration Available   " OFF \
		"HTTPPROXY" "  TCP/8080, Additional Configuration Available   " OFF \
		"MSSQL" "  TCP/1433                                         " OFF \
		"MySQL" "  TCP/3306, Additional Configuration Available   " OFF \
		"NTP" "  UDP/123                                        " OFF \
		"REDIS" "  TCP/6379                                       " OFF \
		"SNMP" "  UDP/161                                        " OFF \
		"SSH" "  TCP/22,   Additional Configuration Available   " OFF \
		"TELNET" "  TCP/23,   Additional Configuration Available   " OFF \
		"TFTP" "  UDP/69                                         " OFF \
		"VNC" "  TCP/5900                                         " OFF 3>&1 1>&2 2>&3 )

	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus
}

whiptail_install_type() {

	[ -n "$TESTING" ] && return

	# What kind of install are we doing?
	if [[ "$OSVER" != "focal" ]]; then
		install_type=$(whiptail --title "$whiptail_title" --menu \
		"What kind of installation would you like to do?\n\nFor more information, please see:\n$DOC_BASE_URL/architecture.html" 18 65 5 \
			"IMPORT" "Import PCAP or log files " \
			"EVAL" "Evaluation mode (not for production) " \
			"STANDALONE" "Standalone production install " \
			"DISTRIBUTED" "Distributed deployment " \
			"DESKTOP" "Security Onion Desktop" \
			3>&1 1>&2 2>&3
		)
	elif [[ "$OSVER" == "focal" ]]; then
		install_type=$(whiptail --title "$whiptail_title" --menu \
		"What kind of installation would you like to do?\n\nFor more information, please see:\n$DOC_BASE_URL/architecture.html" 18 65 5 \
			"DISTRIBUTED" "Distributed install submenu " \
			3>&1 1>&2 2>&3
		)
	fi

	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus

	if [[ $install_type == "DISTRIBUTED" ]]; then
		whiptail_install_type_dist
		if [[ $dist_option == "NEWDEPLOYMENT" ]]; then
			whiptail_install_type_dist_new
		else
			whiptail_install_type_dist_existing
		fi
	fi

	export install_type
}

whiptail_install_type_dist() {

	[ -n "$TESTING" ] && return

	if [[ "$OSVER" != "focal" ]]; then
	dist_option=$(whiptail --title "$whiptail_title" --menu "Do you want to start a new deployment or join this box to \nan existing deployment?" 11 75 2 \
		"New Deployment         " "Create a new Security Onion deployment" \
		"Existing Deployment    " "Join to an existing Security Onion deployment " \
		 3>&1 1>&2 2>&3
	)
	elif [[ "$OSVER" == "focal" ]]; then
	dist_option=$(whiptail --title "$whiptail_title" --menu "Since this is Ubuntu, this box can only be connected to \nan existing deployment." 11 75 2 \
		"Existing Deployment    " "Join to an existing Security Onion deployment " \
		 3>&1 1>&2 2>&3
	)
	fi

	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus

	dist_option=$(echo "${dist_option^^}" | tr -d ' ')
}

whiptail_install_type_dist_new() {
	[ -n "$TESTING" ] && return

	local mngr_msg
	read -r -d '' mngr_msg <<- EOM
	Choose a distributed manager type to start a new grid.
	
	See $DOC_BASE_URL/architecture.html for details.

	Note: MANAGER is the recommended option for most users. MANAGERSEARCH should only be used in very specific situations.
	EOM
	
	install_type=$(whiptail --title "$whiptail_title" --menu "$mngr_msg" 20 75 3 \
		"MANAGER" "New grid, requires separate search node(s) " \
		"MANAGERSEARCH" "New grid, separate search node(s) are optional " \
		"MANAGERHYPE" "Manager with hypervisor - Security Onion Pro required " \
		3>&1 1>&2 2>&3
	)

	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus
}

whiptail_install_type_dist_existing() {
	[ -n "$TESTING" ] && return

	local node_msg
	read -r -d '' node_msg <<- EOM
	Choose a distributed node type to join to an existing grid. See $DOC_BASE_URL/architecture.html for details.

	Note: Heavy nodes (HEAVYNODE) are NOT recommended for most users.
	EOM
	
	install_type=$(whiptail --title "$whiptail_title" --menu "$node_msg" 19 75 7 \
		"SENSOR" "Add a Sensor Node for monitoring network traffic " \
		"SEARCHNODE" "Add a Search Node with parsing " \
		"FLEET" "Dedicated Elastic Fleet Node " \
		"HEAVYNODE" "Sensor + Search Node " \
		"IDH" "Intrusion Detection Honeypot Node " \
		"RECEIVER" "Receiver Node " \
		"HYPERVISOR" "Hypervisor Node - Security Onion Pro required " \
		3>&1 1>&2 2>&3
		# "HOTNODE" "Add Hot Node (Uses Elastic Clustering)" \ # TODO
		# "WARMNODE" "Add Warm Node to existing Hot or Search node" \ # TODO
		# "WAZUH" "Stand Alone Wazuh Server" \ # TODO
		# "STRELKA" "Stand Alone Strelka Node" \ # TODO
	)
	if [ "$install_type" = 'EVAL' ]; then
		is_eval=true
		STRELKARULES=1
	elif [ "$install_type" = 'STANDALONE' ]; then
		is_sensor=true
	elif [ "$install_type" = 'MANAGERSEARCH' ]; then
		is_standalone=true
		is_elasticsearch=true
	elif [ "$install_type" = 'MANAGER' ]; then
		is_manager=true
	elif [ "$install_type" = 'SENSOR' ]; then
		is_sensor=true
	elif [[ "$install_type" =~ ^('SEARCHNODE'|'HOTNODE'|'WARMNODE')$ ]]; then
		is_elasticsearch=true
	elif [ "$install_type" = 'HEAVYNODE' ]; then
		is_heavy=true
	elif [ "$install_type" = 'FLEET' ]; then
		is_fleet=true
	elif [ "$install_type" = 'IDH' ]; then
		is_idh=true
	elif [ "$install_type" = 'IMPORT' ]; then
		is_import=true
	elif [ "$install_type" = 'RECEIVER' ]; then
		is_receiver=true
	elif [ "$install_type" = 'DESKTOP' ]; then
		is_desktop=true
	fi

	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus
}

whiptail_invalid_input() { # TODO: This should accept a list of arguments to specify what general pattern the input should follow
	[ -n "$TESTING" ] && return
	
	whiptail --title "$whiptail_title" --msgbox "  Invalid input, please try again." 7 40
}

whiptail_invalid_proxy() {
	[ -n "$TESTING" ] && return

	local message
	read -r -d '' message <<- EOM
	Could not reach test url using proxy ${proxy_addr}. 
	
	Error was: ${proxy_test_err}
	EOM

	whiptail --title "$whiptail_title" --yesno "$message" --yes-button "Enter Again" --no-button "Skip" 11 60
}

whiptail_invalid_string() {
	[ -n "$TESTING" ] && return
	
	whiptail --title "$whiptail_title" --msgbox "Invalid input, please try again.\n\nThe $1 cannot contain spaces." 9 45

}

whiptail_invalid_pass_characters_warning() {

	[ -n "$TESTING" ] && return

	whiptail --title "$whiptail_title" --msgbox "Password is invalid. Please exclude single quotes, double quotes, dollar signs, and backslashes from the password." 8 75
}

whiptail_invalid_pass_warning() {

	[ -n "$TESTING" ] && return

	whiptail --title "$whiptail_title" --msgbox "Please choose a more secure password." 8 75
}

whiptail_invalid_user_warning() {

	[ -n "$TESTING" ] && return
	
	whiptail --title "$whiptail_title" --msgbox "Please enter a valid email address." 8 75
}

whiptail_invalid_hostname() {
	[ -n "$TESTING" ] && return

	local is_manager_hostname
	is_manager_hostname="$1"

	local error_message
	read -r -d '' error_message <<- EOM
	Please choose a valid hostname. It cannot be localhost. It must contain only the ASCII letters 'A-Z' and 'a-z' (case-sensitive), the digits '0' through '9', and hyphen ('-').
	EOM

	if [[ $is_manager_hostname = 0 ]]; then
		local error_message
		read -r -d '' error_message <<- EOM
		Please enter a valid hostname. The manager hostname cannot be localhost or the chosen hostname for this machine. 
		EOM

	fi

	whiptail --title "$whiptail_title" \
	--msgbox "$error_message" 10 75
}

whiptail_log_size_limit() {

	[ -n "$TESTING" ] && return

	case $install_type in
		STANDALONE | EVAL | HEAVYNODE)
			percentage=50
		;;
		*)
			percentage=80
		;;
	esac

	read -r -d '' message <<- EOM
	Please specify the amount of disk space (in GB) you would like to allocate for Elasticsearch data storage.

	By default, this is set to ${percentage}% of the disk space allotted for /nsm.
	EOM
	
	log_size_limit=$(whiptail --title "$whiptail_title" --inputbox "$message" 11 75 "$1" 3>&1 1>&2 2>&3)

	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus

}

whiptail_first_menu_iso() {
	[ -n "$TESTING" ] && return

	option=$(whiptail --title "$whiptail_title" --menu "Select an option" 10 75 2 \
		"Install              " "Run the standard Security Onion installation " \
		"Configure Network    " "Configure networking only " \
		 3>&1 1>&2 2>&3
	)
	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus

	option=$(echo "${option^^}" | tr -d ' ')
}

whiptail_make_changes() {

	[ -n "$TESTING" ] && return

	whiptail --title "$whiptail_title" --yesno "We are going to set this machine up as a $install_type. Please press YES to make changes or NO to cancel." 8 75

	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus

}

whiptail_management_interface_dns() {

	[ -n "$TESTING" ] && return

	MDNS=$(whiptail --title "$whiptail_title" --inputbox \
	"Enter your DNS servers separated by commas:" 10 60 "$1" 3>&1 1>&2 2>&3)

	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus

}

whiptail_management_interface_dns_search() {

	[ -n "$TESTING" ] && return

	MSEARCH=$(whiptail --title "$whiptail_title" --inputbox \
	"Enter your DNS search domain:" 10 60 "$1" 3>&1 1>&2 2>&3)

	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus
}

whiptail_management_interface_gateway() {

	[ -n "$TESTING" ] && return

	MGATEWAY=$(whiptail --title "$whiptail_title" --inputbox \
	"Enter your gateway's IPv4 address:" 10 60 "$1" 3>&1 1>&2 2>&3)

	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus
}

whiptail_management_interface_ip_mask() {
	[ -n "$TESTING" ] && return

	local msg
	read -r -d '' msg <<- EOM
	What IPv4 address would you like to assign to this Security Onion installation?

	Please enter the IPv4 address with CIDR mask
	(e.g. 192.168.1.2/24):
	EOM

	manager_ip_mask=$(whiptail --title "$whiptail_title" --inputbox "$msg" 12 60 "$1" 3>&1 1>&2 2>&3)

	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus
}

whiptail_management_nic() {

	[ -n "$TESTING" ] && return

	filter_unused_nics

	MNIC=$(whiptail --title "$whiptail_title" --menu "Please select the NIC you would like to use for management.\n\nUse the arrow keys to move around and the Enter key to select." 20 75 12 "${nic_list_management[@]}" 3>&1 1>&2 2>&3 )	
	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus

	while [ -z "$MNIC" ]
	do
		MNIC=$(whiptail --title "$whiptail_title" --menu "Please select the NIC you would like to use for management.\n\nUse the arrow keys to move around and the Enter key to select." 22 75 12 "${nic_list_management[@]}" 3>&1 1>&2 2>&3 )	
		local exitstatus=$?
		whiptail_check_exitstatus $exitstatus
	done

}

whiptail_net_method() {
	[ -n "$TESTING" ] && return

	local pkg_mngr
	if [[ $OS = 'centos' ]]; then pkg_mngr="yum"; else pkg_mngr='apt'; fi

	read -r -d '' options_msg <<- EOM
	"Direct" - Internet requests connect directly to the Internet.

	EOM
	local options=(
		" Direct " ""
	)
	local proxy_desc="proxy the traffic for git, docker client, wget, curl, ${pkg_mngr}, and various other SO components through a separate server in your environment."

	read -r -d '' options_msg <<- EOM
		${options_msg}
		"Proxy" - ${proxy_desc}
	EOM
	options+=(
		" Proxy " ""
	)

	local height=17

	local msg
	read -r -d '' msg <<- EOM
	How would you like to connect to the Internet? 

	$options_msg
	EOM

	local option_count=$(( ${#options[@]} / 2 ))

	network_traffic=$(whiptail --title "$whiptail_title" --menu "$msg" $height 75 $option_count "${options[@]}" 3>&1 1>&2 2>&3)

	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus
	
	network_traffic=$(echo "${network_traffic^^}" | tr -d ' ' | tr '+' '_')
}

whiptail_net_setup_complete() {
	[ -n "$TESTING" ] && return

	whiptail --title "$whiptail_title" \
		--msgbox "Successfully set up networking, setup will now exit." 7 75
	exit 0
}

whiptail_management_server() {

	[ -n "$TESTING" ] && return

	MSRV=$(whiptail --title "$whiptail_title" --inputbox \
	"Enter your Manager Server hostname: \nIt is CASE SENSITIVE!" 10 75 "$1" 3>&1 1>&2 2>&3)

	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus

}

whiptail_manager_ip() {
	[ -n "$TESTING" ] && return

	MSRVIP=$(whiptail --title "$whiptail_title" --inputbox \
		"Enter your Manager Server IP Address:" 10 60 "$1" 3>&1 1>&2 2>&3)

	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus
}

# Ask if you want to do advanced setup of the Manager
whiptail_manager_adv() {

	[ -n "$TESTING" ] && return

	MANAGERADV=$(whiptail --title "$whiptail_title" --menu \
	"Choose which type of manager to install:" 20 75 4 \
	"BASIC" "Install manager with recommended settings" \
	"ADVANCED" "Do additional configuration to the manager" 3>&1 1>&2 2>&3 )

	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus

}

whiptail_manager_error() {

	[ -n "$TESTING" ] && return

	local msg
	read -r -d '' msg <<- EOM
	Setup could not determine if the manager $MSRV is in a good state.

	Continuing without verifying all services on the manager are running may result in a failure.

	Would you like to continue anyway?
	EOM

	whiptail --title "$whiptail_title" --yesno "$msg" 13 75 || whiptail_check_exitstatus 1
}

whiptail_manager_updates_warning() {
	[ -n "$TESTING" ] && return

	whiptail --title "$whiptail_title"\
	--msgbox "Updating through the manager node requires the manager to have access to the Internet. Press the Enter key to continue."\
	8 75

	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus
}

whiptail_manager_unreachable() {
	[ -n "$TESTING" ] && return

	local msg
	read -r -d '' msg <<- EOM
	Setup is unable to access the manager. This most likely means that you need to allow this machine to connect through the manager's firewall. 

	You can either go to SOC --> Administration --> Configuration and choose the correct firewall option from the list OR you can run the following command on the manager:
	
	sudo so-firewall-minion --role=$install_type --ip=$MAINIP
	
	Would you like to retry?
	EOM
	whiptail --title "$whiptail_title" --yesno "$msg" 20 75
	local status=$?
	if [[ "$status" == 1 ]]; then
		whiptail_cancel
	else
		check_manager_connection
	fi
}

whiptail_metadata_tool() {

	[ -n "$TESTING" ] && return

	read -r -d '' message <<- EOM
		What tool would you like to use to generate metadata?
		
		This question is asking specifically about metadata, which would be things like the connection log, DNS log, HTTP log, etc. This does not include NIDS alerts.
		
		If you choose Zeek for metadata, Suricata will still run to generate NIDS alerts.

		If you choose Suricata for metadata, it will generate NIDS alerts and metadata, and Zeek will not run at all.
	EOM

	# Legacy variable naming
	ZEEKVERSION=$(whiptail --title "$whiptail_title" --menu "$message" 20 75 2 \
	"Zeek      " "Use Zeek (Bro) for metadata and Suricata for NIDS alerts" \
	"Suricata  " "Use Suricata for both metadata and NIDS alerts" 3>&1 1>&2 2>&3)

	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus

	ZEEKVERSION=$(echo "${ZEEKVERSION^^}" | tr -d ' ')
}

whiptail_network_notice() {

	[ -n "$TESTING" ] && return

	whiptail --title "$whiptail_title" --yesno "Since this is a network install we assume the management interface, DNS, Hostname, etc are already set up. Select Yes if you've already configured these settings. Otherwise, select No to quit." 10 75

	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus

}

whiptail_net_reinit() {
	[ -n "$TESTING" ] && return

	whiptail --title "$whiptail_title" --yesno "The management interface has already been configured. Do you want to reconfigure it?" 8 75
}

whiptail_node_description() {
	[ -n "$TESTING" ] && return

	NODE_DESCRIPTION=$(whiptail --title "$whiptail_title" \
		--inputbox "Enter a short description for the node or press ENTER to leave blank:" 10 75 3>&1 1>&2 2>&3)

	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus
}

whiptail_ntp_ask() {
	[ -n "$TESTING" ] && return

	whiptail --title "$whiptail_title" --yesno "Would you like to configure ntp servers?" 7 44
}

whiptail_ntp_servers() {
	[ -n "$TESTING" ] && return

	ntp_string=$(whiptail --title "$whiptail_title" \
		--inputbox "Input the NTP server(s) you would like to use, separated by commas:" 8 75 "$1" 3>&1 1>&2 2>&3)

	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus
}

#TODO: helper function to display error message or exit if batch mode
# exit_if_batch <"Error string"> <Error code (int)>

whiptail_error_message() {

	local error_message=$1 # message to be displayed

	whiptail --title "$whiptail_title" --msgbox "$error_message" 10 75

}

whiptail_passwords_dont_match() {

	whiptail --title "$whiptail_title" --msgbox "Passwords don't match. Please re-enter." 8 75

}

whiptail_preflight_err() {
	[ -n "$TESTING" ] && return 1

	read -r -d '' message <<- EOM
	The so-preflight script failed checking one or more URLs required by setup. Check $setup_log for more details.

	Would you like to exit setup?
	EOM

	whiptail --title "$whiptail_title" \
		--yesno "$message" 11 75 \
		--yes-button "Continue" --no-button "Exit" --defaultno
}

whiptail_proxy_ask() {
	[ -n "$TESTING" ] && return

	local pkg_mngr
	if [[ $OS = 'centos' ]]; then pkg_mngr="yum"; else pkg_mngr='apt'; fi
	whiptail --title "$whiptail_title" --yesno "Do you want to proxy the traffic for git, docker client, wget, curl, ${pkg_mngr}, and various other SO components through a separate server in your environment?" 9 65 --defaultno
}

whiptail_proxy_addr() {
	[ -n "$TESTING" ] && return

	local message
	read -r -d '' message <<- EOM
	Please input the proxy server you wish to use, including the URL prefix (ex: https://your.proxy.com:1234).

	If your proxy requires a username and password do not include them in your input. Setup will ask for those values next.
	EOM

	proxy_addr=$(whiptail --title "$whiptail_title" --inputbox "$message" 13 60 "$1" 3>&1 1>&2 2>&3)

	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus
}

whiptail_proxy_auth_ask() {
	[ -n "$TESTING" ] && return

	whiptail --title "$whiptail_title" --yesno "Does your proxy require authentication?" 7 60
}

whiptail_proxy_auth_user() {
	[ -n "$TESTING" ] && return
	
	proxy_user=$(whiptail --title "$whiptail_title" --inputbox "Please input the proxy user:" 8 60 "$1" 3>&1 1>&2 2>&3)

	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus
}

whiptail_proxy_auth_pass() {
	local arg=$1

	[ -n "$TESTING" ] && return

	proxy_pass=$(whiptail --title "$whiptail_title" --passwordbox "Please input the proxy password:" 8 60 3>&1 1>&2 2>&3)

	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus
}

whiptail_reinstall() {
	[ -n "$TESTING" ] && return

	read -r -d '' message <<- EOM
	Setup has detected a previous install. Continuing the install will remove the previous install configuration.

	Selecting continue is a destructive action.

	Would you like to continue?
	EOM

	whiptail --title "$whiptail_title" \
		--yesno "$message" 13 75 \
		--yes-button "Continue" --no-button "Exit" --defaultno

	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus
}

whiptail_sensor_config() {

	[ -n "$TESTING" ] && return

	NSMSETUP=$(whiptail --title "$whiptail_title" --menu \
	"What type of configuration would you like to use?" 20 75 4 \
	"BASIC" "Install NSM components with recommended settings" \
	"ADVANCED" "Configure each component individually" 3>&1 1>&2 2>&3 )

	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus

}

whiptail_sensor_nics() {

	[ -n "$TESTING" ] && return

	filter_unused_nics

	if [[ $is_ec2 ]]; then
		local menu_text="Please select NIC for the Monitor Interface:"
		local list_type="radiolist"
	else
		local menu_text="Please add NICs to the Monitor Interface:"
		local list_type="checklist"
	fi

	BNICS=$(whiptail --title "$whiptail_title" --$list_type "$menu_text" 20 75 12 "${nic_list[@]}" 3>&1 1>&2 2>&3)
	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus

	while [ -z "$BNICS" ]
	do
		BNICS=$(whiptail --title "$whiptail_title" --$list_type "$menu_text" 20 75 12 "${nic_list[@]}" 3>&1 1>&2 2>&3 )
		local exitstatus=$?
		whiptail_check_exitstatus $exitstatus
	done

	BNICS=$(echo "$BNICS" | tr -d '"')

	IFS=' ' read -ra BNICS <<< "$BNICS"

	for bond_nic in "${BNICS[@]}"; do
		for dev_status in "${nmcli_dev_status_list[@]}"; do
			if [[ $dev_status == "${bond_nic}:unmanaged" ]]; then
				whiptail \
					--title "$whiptail_title" \
					--msgbox "$bond_nic is unmanaged by Network Manager. Please remove it from other network management tools then re-run setup." \
					8 75
				exit
			fi
		done
	done
}

whiptail_set_hostname() {

	[ -n "$TESTING" ] && return

	HOSTNAME=$(whiptail --title "$whiptail_title" --inputbox \
		"Enter the hostname (not FQDN) you would like to set:" 10 75 "$1" 3>&1 1>&2 2>&3)

	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus
}

whiptail_set_redirect() {

	[ -n "$TESTING" ] && return

	local options=()
	options+=( "IP" "Use IP address to access the web interface" )
	[[ $no_use_hostname != true ]] && options+=( "HOSTNAME" "Use hostname to access the web interface" )
	options+=("OTHER" "Use a different name like a FQDN or Load Balancer" )

	REDIRECTINFO=$(whiptail --title "$whiptail_title" --menu \
		"How would you like to access the web interface?\n\nWhatever you choose here will be the only way that you can access the web interface.\n\nIf you choose something other than IP address, then you'll need to ensure that you can resolve the name via DNS or hosts entry. If you are unsure, please select IP." 20 75 4 \
		"${options[@]}" \
		3>&1 1>&2 2>&3 
	)
	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus
}

whiptail_set_redirect_host() {

	[ -n "$TESTING" ] && return

	REDIRECTHOST=$(whiptail --title "$whiptail_title" --inputbox \
	"Enter the Hostname, IP, or FQDN you would like to use for the web interface:" 10 75 "$1" 3>&1 1>&2 2>&3)
	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus
}

whiptail_setup_complete() {

	[ -n "$TESTING" ] && return


	if [[ $waitforstate ]]; then
		# Manager-type Nodes - Install Summary
		if [[ -n $ALLOW_CIDR ]]; then
			local sentence_prefix="Access"
		else
			local sentence_prefix="Run so-allow to access"
		fi
	
		read -r -d '' message <<- EOM
			${install_type} setup is now complete!
			
			${sentence_prefix} the Security Onion Console (SOC) web interface by navigating to:
			https://${REDIRECTIT}

			Then login with the following username and password.

			SOC Username: ${WEBUSER}
			SOC Password: Use the password that was entered during setup
			
			Press TAB and then the ENTER key to exit this screen.
		EOM
		whiptail --title "$whiptail_title" --msgbox "$message" 24 75 --scrolltext
	else
		if [[ $is_idh ]]; then
			local accessMessage="\nSSH for this node has been moved to TCP/2222, accessible only from the Manager node.\n"
		else
			local accessMessage=""
		fi
		MINIONFINGERPRINT=$(salt-call --local key.finger --out=newline_values_only)
		read -r -d '' message <<- EOM
			${install_type} initialization is now complete!
			
			To finish configuration, open the Security Onion Console web interface
			and navigate to Administration -> Grid Members.
			
			Then find this node in the Pending Members list, 
			click the Review button, and then click the Accept button.
			
			Node Hostname: $HOSTNAME
			Node Fingerprint:
			$MINIONFINGERPRINT
			$accessMessage
			Press TAB and then the ENTER key to exit this screen.
		EOM

		whiptail --title "$whiptail_title" --msgbox "$message" 24 75 --scrolltext
	fi
}

whiptail_setup_failed() {

	[ -n "$TESTING" ] && return

	local check_err_msg
	local height

	[ -f "$error_log" ] && check_err_msg="A summary of errors can be found in $error_log.\n"

	if [[ -n $check_err_msg ]]; then height=11; else height=10; fi

	read -r -d '' message <<- EOM
			Install had a problem. Please see $setup_log for details.\n
			$check_err_msg
			Select Ok to exit.
		EOM

	whiptail --title "$whiptail_title" --msgbox "$message" $height 75
}

whiptail_so_allow_yesno() {
	[ -n "$TESTING" ] && return

	whiptail --title "$whiptail_title" \
		--yesno "Do you want to allow access to this Security Onion installation via the web interface?" \
		8 75
}

whiptail_so_allow() {

	[ -n "$TESTING" ] && return
	
	ALLOW_CIDR=$(whiptail --title "$whiptail_title" \
		--inputbox "Enter a single IP address or an IP range, in CIDR notation, to allow:" \
		10 75 "$1" 3>&1 1>&2 2>&3)
	local exitstatus=$?
	
	export ALLOW_ROLE='analyst'
	export ALLOW_CIDR

	whiptail_check_exitstatus $exitstatus
}

whiptail_storage_requirements() {
	local mount=$1
	local current_val=$2
	local needed_val=$3

	[ -n "$TESTING" ] && return

	read -r -d '' message <<- EOM
		Free space on mount point '${mount}' is currently ${current_val}.

		You need ${needed_val} to meet minimum requirements.

		Visit $DOC_BASE_URL/hardware.html for more information.

		Select YES to continue anyway, or select NO to cancel.
	EOM

	whiptail \
		--title "$whiptail_title" \
		--yesno "$message" \
		14 75

	local exitstatus=$?
	whiptail_check_exitstatus $exitstatus
}

whiptail_ubuntu_notsupported() {
	[ -n "$TESTING" ] && return
	
	read -r -d '' message <<- EOM
		Ubuntu is not supported for this node type.

		Please use a supported OS or install via ISO.
	EOM
	whiptail --title "$whiptail_title"  --msgbox "$message" 14 75
}

whiptail_ubuntu_warning() {
	[ -n "$TESTING" ] && return
	
	read -r -d '' message <<- EOM
		Ubuntu support for this node type is limited.

		Please consider using a fully supported OS or install via ISO.
	EOM
	whiptail --title "$whiptail_title"  --msgbox "$message" 14 75

}

whiptail_unsupported_os_warning() {

	[ -n "$TESTING" ] && return

	read -r -d '' unsupported_os_continue <<- EOM
	
	WARNING: An unsupported operating system has been detected. 
	Security Onion may not install or operate as expected. 

	Would you like to continue the install?

	EOM
	whiptail --title "$whiptail_title" \
		--yesno "$unsupported_os_continue" 14 75 --defaultno

	local exitstatus=$?
	return $exitstatus

}

whiptail_uppercase_warning() {

	[ -n "$TESTING" ] && return
	
	local type=$1

	local msg
	if [[ -z $type ]]; then
		type="hostname"
		read -r -d '' msg <<- EOM
		The value "$HOSTNAME" contains uppercase characters.
		
		Continuing with this hostname could render the system unusable in certain cases, and will also disable the option later in setup to access Security Onion's web interface via the hostname.
		EOM
	else
		read -r -d '' msg <<- EOM
		The value "$REDIRECTHOST" contains uppercase characters.
		
		Continuing with this value could render the system unusable in certain cases.
		EOM
	fi

	read -r -d '' msg <<- EOM
	$msg

	For best results, it is recommended to only use lowercase ${type}s with Security Onion.
	EOM

	whiptail --title "$whiptail_title" --yesno "$msg" --yes-button "Continue anyway" --no-button "Go back" --defaultno 16 75
}

whiptail_you_sure() {

	[ -n "$TESTING" ] && return

	read -r -d '' you_sure_text <<- EOM
		Welcome to Security Onion Setup!

		You can use Setup for several different use cases, from a small standalone installation to a large distributed deployment for your enterprise. You can learn more in the documentation at:
		$DOC_BASE_URL

		Setup uses keyboard navigation and you can use arrow keys to move around. Certain screens may provide a list and ask you to select one or more items from that list. You can use the Space bar to select items and the Enter key to proceed to the next screen.
		
		Would you like to continue?
	EOM

	whiptail \
		--title "$whiptail_title" \
		--yesno "$you_sure_text" \
		20 75

	local exitstatus=$?
	return $exitstatus

}
