#!/bin/bash
{
	#////////////////////////////////////
	# DietPi Lets Encrypt
	#
	#////////////////////////////////////
	# Created by Daniel Knight / daniel.knight@dietpi.com / dietpi.com
	#
	#////////////////////////////////////
	#
	# Info:
	# - filename /DietPi/dietpi/dietpi-letsencrypt
	# - Menu Frontend for Letsencrypt with CLI options for use on DietPi systems.
	#
	# usage:
	# - /DietPi/dietpi/dietpi-letsencrypt   = Menu
	# - /DietPi/dietpi/dietpi-letsencrypt 1 = Create/Renew/Apply cert
	#////////////////////////////////////

	#Grab Input
	INPUT=0
	if [[ $1 =~ ^-?[0-9]+$ ]]; then
		INPUT=$1
	fi

	#Import DietPi-Globals ---------------------------------------------------------------
	. /DietPi/dietpi/func/dietpi-globals
	G_CHECK_ROOT_USER
	G_CHECK_ROOTFS_RW
	export G_PROGRAM_NAME='DietPi-Letsencrypt'
	#Import DietPi-Globals ---------------------------------------------------------------

	#/////////////////////////////////////////////////////////////////////////////////////
	#Globals
	#/////////////////////////////////////////////////////////////////////////////////////
	DP_LOGFILE="/var/log/dietpi-letsencrypt.log"
	DP_MONTHLY_CRON="/etc/cron.monthly/dietpi-letsencrypt"
	DP_LETSENCRYPT_BINARY="/usr/bin/certbot"
	if (( $G_DISTRO < 4 )); then
		DP_LETSENCRYPT_BINARY="/etc/certbot_scripts/certbot-auto"
	fi
	DP_WEBSERVER_INDEX=0 #0=apache2 1=lighttpd 2=nginx 3=minio

	LETSENCRYPT_INSTALLED=0
	if [ -f "$DP_LETSENCRYPT_BINARY" ]; then
		LETSENCRYPT_INSTALLED=1
	fi
	LETSENCRYPT_DOMAIN="mydomain.com"
	LETSENCRYPT_EMAIL="myemail@email.com"
	LETSENCRYPT_REDIRECT=0
	LETSENCRYPT_AUTORENEW=0
	LETSENCRYPT_KEYSIZE=4096

	Run_Lets_Encrypt(){

		G_DIETPI-NOTIFY 3 "$PROGRAM_NAME" "Running cert"

		#Conditions that must be met before allowing run
		local run_conditions_met=1

		/DietPi/dietpi/dietpi-services start

		# - Obtain installed and running webserver index
		if (( $(ps aux | grep -ci -m1 '[a]pache') )); then

			DP_WEBSERVER_INDEX=0
			G_DIETPI-NOTIFY 0 "Apache2 webserver detected"
			if (( $G_DISTRO >= 4 )); then
				DP_LETSENCRYPT_BINARY="$DP_LETSENCRYPT_BINARY --apache"
			fi

		elif (( $(ps aux | grep -ci -m1 '[l]ighttpd') )); then

			DP_WEBSERVER_INDEX=1
			G_DIETPI-NOTIFY 0 "Lighttpd webserver detected"

		elif (( $(ps aux | grep -ci -m1 '[n]ginx') )); then

			DP_WEBSERVER_INDEX=2
			G_DIETPI-NOTIFY 0 "Nginx webserver detected"
			if (( $G_DISTRO >= 4 )); then
				DP_LETSENCRYPT_BINARY="$DP_LETSENCRYPT_BINARY --nginx"
			fi

		elif (( $(ps aux | grep -ci -m1 '[m]inio') )); then

			DP_WEBSERVER_INDEX=3
			G_DIETPI-NOTIFY 0 "Minio S3 server detected"

		else

			run_conditions_met=0

		fi

		#Failed. No compatible webserver is currently running
		if (( ! $run_conditions_met )); then

			echo -e "Error: No compatible and/or active webserver was found. Aborting." >> "$DP_LOGFILE"
			if (( $INPUT == 0 )); then

				whiptail --title "Error" --msgbox "Error: No compatible and/or active webserver was found. Aborting." --backtitle "$PROGRAM_NAME" 8 60

			fi

		#Cert up
		else

			#------------------------------------------------------------------------------------------------------
			#apache2
			if (( $DP_WEBSERVER_INDEX == 0 )); then

				local dp_defaultsite="/etc/apache2/sites-available/000-default.conf"

				#Add ServerName if it doesnt exist. This is required to prevent letsencrypt compaining about vhost with no domain.
				if (( ! $(cat "$dp_defaultsite" | grep -ci -m1 'ServerName') )); then

					sed -i "/ServerAdmin /a ServerName" "$dp_defaultsite"

					#log
					echo -e "ServerName entry not found in $dp_defaultsite. Adding it now." >> "$DP_LOGFILE"

				fi

				#Apply domain name
				sed -i "/ServerName/c\        ServerName $LETSENCRYPT_DOMAIN" "$dp_defaultsite"

				#Restart apache2 to apply ServerName changes.
				systemctl restart apache2

				local cli_redirect="--no-redirect"
				if (( $LETSENCRYPT_REDIRECT )); then

					cli_redirect="--redirect"

				fi

				#Cert me up Apache2
				$DP_LETSENCRYPT_BINARY --duplicate --agree-tos $cli_redirect --rsa-key-size $LETSENCRYPT_KEYSIZE --email $LETSENCRYPT_EMAIL -d $LETSENCRYPT_DOMAIN

			#------------------------------------------------------------------------------------------------------
			#Lighttpd
			elif (( $DP_WEBSERVER_INDEX == 1 )); then

				# - Cert me up
				/DietPi/dietpi/dietpi-services stop

				$DP_LETSENCRYPT_BINARY certonly --standalone --duplicate --agree-tos $cli_redirect --rsa-key-size $LETSENCRYPT_KEYSIZE --email $LETSENCRYPT_EMAIL -d $LETSENCRYPT_DOMAIN

				# - Create combined key
				cd /etc/letsencrypt/live/"$LETSENCRYPT_DOMAIN"
				cat privkey.pem cert.pem > combined.pem

				cat << _EOF_ > /etc/lighttpd/conf-enabled/letsencrypt.conf
\$SERVER["socket"] == ":443" {
		ssl.engine = "enable"
		ssl.pemfile = "/etc/letsencrypt/live/$LETSENCRYPT_DOMAIN/combined.pem"
		ssl.ca-file =  "/etc/letsencrypt/live/$LETSENCRYPT_DOMAIN/fullchain.pem"
		#ssl.cipher-list = "ECDHE-RSA-AES256-SHA384:AES256-SHA256:HIGH:!MD5:!aNULL:!EDH:!AESGCM"
		ssl.cipher-list = "ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS"
		ssl.honor-cipher-order = "enable"
		ssl.use-sslv2 = "disable"
		ssl.use-sslv3 = "disable"
}
_EOF_

				#Redirect
				rm /etc/lighttpd/conf-enabled/redirect.conf
				if (( $LETSENCRYPT_REDIRECT )); then

					cat << _EOF_ > /etc/lighttpd/conf-enabled/redirect.conf
\$HTTP["scheme"] == "http" {
	# capture vhost name with regex conditiona -> %0 in redirect pattern
	# must be the most inner block to the redirect rule
	\$HTTP["host"] =~ ".*" {
		url.redirect = (".*" => "https://%0\$0")
	}
}
_EOF_

				fi

				/etc/init.d/lighttpd force-reload


			#------------------------------------------------------------------------------------------------------
			# Nginx

			elif (( $DP_WEBSERVER_INDEX == 2 )); then

				local nginx_defaultsite="/etc/nginx/sites-available/default"

				# Apply domain name
				sed -i "/server_name/c\        server_name $LETSENCRYPT_DOMAIN;" "$nginx_defaultsite"

				#Restart nginx to apply ServerName changes.
				systemctl restart nginx

				local cli_redirect="--no-redirect"

				if (( $LETSENCRYPT_REDIRECT )); then

					cli_redirect="--redirect"

				fi

				#Cert me up Nginx
				$DP_LETSENCRYPT_BINARY --duplicate --agree-tos $cli_redirect --rsa-key-size $LETSENCRYPT_KEYSIZE --email $LETSENCRYPT_EMAIL -d $LETSENCRYPT_DOMAIN


			#------------------------------------------------------------------------------------------------------
			#Minio
			elif (( $DP_WEBSERVER_INDEX == 3 )); then
				# - Cert me up
				/DietPi/dietpi/dietpi-services stop

				$DP_LETSENCRYPT_BINARY certonly --standalone --preferred-challenges tls-sni --staple-ocsp --agree-tos $cli_redirect --rsa-key-size $LETSENCRYPT_KEYSIZE --email $LETSENCRYPT_EMAIL -d $LETSENCRYPT_DOMAIN

				# Locate them correctly (THIS didn't work as symlinks)
				cp /etc/letsencrypt/live/$LETSENCRYPT_DOMAIN/fullchain.pem /home/minio-user/.minio/certs/public.crt
				cp /etc/letsencrypt/live/$LETSENCRYPT_DOMAIN/privkey.pem /home/minio-user/.minio/certs/private.key

				# Own those certs!
				chown minio-user:minio-user /home/minio-user/.minio/certs/public.crt
				chown minio-user:minio-user /home/minio-user/.minio/certs/private.key

				# Add SSL to config file
				grep -v "MINIO_OPTS" /etc/default/minio > /etc/default/minio.temp1
				grep -v "port" /etc/default/minio.temp1 > /etc/default/minio.temp2
				rm /etc/default/minio.temp1
				mv /etc/default/minio.temp2 /etc/default/minio
				cat << _EOF_ >> /etc/default/minio
# Use if you want to run Minio on a custom port.
MINIO_OPTS="--address :443"
_EOF_

				# Allow SSL binding for non root user
				setcap CAP_NET_BIND_SERVICE=+eip /usr/local/bin/minio

				# Create renewl script
				cat << _EOF_ > /home/minio-user/.minio/dietpi-cert-renewl.sh
# Minio only works with copied and owned certs. Upon renewal the new certs needs to be copied and re-owned
systemctl stop minio.service

# Copy to correct Location
cp /etc/letsencrypt/live/$LETSENCRYPT_DOMAIN/fullchain.pem /home/minio-user/.minio/certs/public.crt
cp /etc/letsencrypt/live/$LETSENCRYPT_DOMAIN/privkey.pem /home/minio-user/.minio/certs/private.key

# Re-Own those certs!
chown minio-user:minio-user /home/minio-user/.minio/certs/public.crt
chown minio-user:minio-user /home/minio-user/.minio/certs/private.key

systemctl start minio.service
_EOF_

			# Change permissions on renewal script
			chmod +x /home/minio-user/.minio/dietpi-cert-renewl.sh
			fi


			#------------------------------------------------------------------------------------------------------
			#ALL | Create cron job
			if (( $LETSENCRYPT_AUTORENEW && $G_DISTRO < 4 )); then

				cat << _EOF_ > "$DP_MONTHLY_CRON"
#!/bin/bash
{
	#////////////////////////////////////
	# DietPi-LetsEncrypt Autorenew script
	#
	#////////////////////////////////////
	#
	# Info:
	# - Location $DP_MONTHLY_CRON
	#
	#////////////////////////////////////

	#----------------------------------------------------------------
	# Main Loop
	#----------------------------------------------------------------
	/DietPi/dietpi/dietpi-letsencrypt 1 &>> $DP_LOGFILE

	# Minio specific applications
	if (( $(ps aux | grep -ci -m1 '[m]inio') )); then
		/home/minio-user/.minio/dietpi-cert-renewl.sh
	fi

	#----------------------------------------------------------------
	exit
	#----------------------------------------------------------------
}
_EOF_
				chmod +x "$DP_MONTHLY_CRON"

			fi

			if (( $INPUT == 0 )); then

				echo -e ""
				read -p "Press any key to continue..."
				echo -e ""

			fi

			#Restart services
			/DietPi/dietpi/dietpi-services restart

		fi

	}

	#/////////////////////////////////////////////////////////////////////////////////////
	# Settings File
	#/////////////////////////////////////////////////////////////////////////////////////
	DP_SETTINGS="/DietPi/dietpi/.dietpi-letsencrypt"

	Read_Settings_File(){

		local sed_index=1

		LETSENCRYPT_DOMAIN=$(sed -n "$sed_index"p $DP_SETTINGS);((sed_index++))
		LETSENCRYPT_EMAIL=$(sed -n "$sed_index"p $DP_SETTINGS);((sed_index++))
		LETSENCRYPT_REDIRECT=$(sed -n "$sed_index"p $DP_SETTINGS);((sed_index++))
		LETSENCRYPT_AUTORENEW=$(sed -n "$sed_index"p $DP_SETTINGS);((sed_index++))
		LETSENCRYPT_KEYSIZE=$(sed -n "$sed_index"p $DP_SETTINGS);((sed_index++))

	}

	Write_Settings_File(){

		cat << _EOF_ > "$DP_SETTINGS"
$LETSENCRYPT_DOMAIN
$LETSENCRYPT_EMAIL
$LETSENCRYPT_REDIRECT
$LETSENCRYPT_AUTORENEW
$LETSENCRYPT_KEYSIZE
_EOF_

	}

	#/////////////////////////////////////////////////////////////////////////////////////
	# MENUS
	#/////////////////////////////////////////////////////////////////////////////////////
	PROGRAM_NAME="DietPi-LetsEncrypt"

	CHOICE=0
	OPTION=0
	TARGETMENUID=0
	PREVIOUS_MENU_SELECTION=""

	Menu_Exit(){

		whiptail --title "Exit $PROGRAM_NAME?" --yesno "Exit $PROGRAM_NAME?" --backtitle "$PROGRAM_NAME" --yes-button "Ok" --no-button "Back" --defaultno 9 55
		CHOICE=$?
		if (( $CHOICE == 0 )); then
			#exit
			TARGETMENUID=-1
		else
			#Return to Main Menu
			TARGETMENUID=0
		fi
	}

	#TARGETMENUID=0
	Menu_Main(){

		local auto_renew_text="Disabled | Manual renewal every 90 days"
		if (( $LETSENCRYPT_AUTORENEW )); then
			auto_renew_text="Enabled | Automatic cron.monthly renewals"
		fi

		local redirect_text="Disabled | Allows http and https usage"
		if (( $LETSENCRYPT_REDIRECT )); then
			redirect_text="Enabled | Forces http redirects to https"
		fi

		OPTION=$(whiptail --title "$PROGRAM_NAME" --menu "Please select a option." --cancel-button "Exit" --default-item "$PREVIOUS_MENU_SELECTION" --backtitle "$PROGRAM_NAME" 14 70 6 \
		"Domain" ": $LETSENCRYPT_DOMAIN" \
		"Email" ": $LETSENCRYPT_EMAIL" \
		"Redirect" ": $redirect_text" \
		"Auto Renew" ": $auto_renew_text" \
		"Key Size" ": $LETSENCRYPT_KEYSIZE" \
		"Apply" "Runs Lets Encrypt with your chosen options." 3>&1 1>&2 2>&3)

		CHOICE=$?
		if (( $CHOICE == 0 )); then

			PREVIOUS_MENU_SELECTION=$OPTION

			case "$OPTION" in
				Domain)
					LETSENCRYPT_DOMAIN="$(Input_Box $LETSENCRYPT_DOMAIN Website-Domain)"
				;;
				Email)
					LETSENCRYPT_EMAIL="$(Input_Box $LETSENCRYPT_EMAIL Email-Address)"
				;;
				"Key Size")
					if (( $LETSENCRYPT_KEYSIZE == 2048 )); then
						LETSENCRYPT_KEYSIZE=4096
					else
						LETSENCRYPT_KEYSIZE=2048
					fi
				;;
				"Auto Renew")
					((LETSENCRYPT_AUTORENEW++))
					if (( $LETSENCRYPT_AUTORENEW > 1 )); then
						LETSENCRYPT_AUTORENEW=0
					fi
				;;
				Redirect)
					((LETSENCRYPT_REDIRECT++))
					if (( $LETSENCRYPT_REDIRECT > 1 )); then
						LETSENCRYPT_REDIRECT=0
					fi
				;;
				Apply)
					whiptail --title "Run Lets Encrypt?" --yesno "LetsEncrypt will now be run. This will:\n- Create your free SSL cert.\n- Automatically apply and enable your SSL cert\n- NB: This process can take a long time, please be patient.\n\nWould you like to continue?" --backtitle "$PROGRAM_NAME" --yes-button "Ok" --no-button "Back" --defaultno 13 65
					CHOICE=$?
					if (( $CHOICE == 0 )); then
						Write_Settings_File
						Run_Lets_Encrypt
					fi
				;;
			esac

		else
			#Exit
			Menu_Exit
		fi

	}

	Input_Box(){

		local input_value=$1
		local input_desc=$2

		OPTION=$(whiptail --inputbox "Please enter your $input_desc" 9 50 "$input_value" --title "Input $input_desc" 3>&1 1>&2 2>&3)
		CHOICE=$?
		if (( $CHOICE == 0 )); then
			input_value=$OPTION
			# - Prevent null values
			if [ -z "$input_value" ]; then
				input_value='NULL'
			fi
		fi
		echo -e "$input_value"

	}

	#/////////////////////////////////////////////////////////////////////////////////////
	# Main Loop
	#/////////////////////////////////////////////////////////////////////////////////////
	#Load Settings file. Generate if required.
	if [ ! -f "$DP_SETTINGS" ]; then

		Write_Settings_File

	else

		Read_Settings_File

	fi

	#-----------------------------------------------------------------------------------
	#Check installed
	if (( ! $LETSENCRYPT_INSTALLED )); then

		#Menu
		if (( $INPUT == 0 )); then

			G_DIETPI-NOTIFY 1 "Certbot binary not found ( $DP_LETSENCRYPT_BINARY )"
			G_DIETPI-NOTIFY 2 "Please install Certbot with DietPi-Software before running this program."
			read -p "Press any key to continue....."

		else

			echo -e "Error: Letsencrypt binary not installed ( $DP_LETSENCRYPT_BINARY )." >> "$DP_LOGFILE"

		fi

	#-----------------------------------------------------------------------------------
	#Menu
	elif (( $INPUT == 0 )); then

		while (( $TARGETMENUID > -1 )); do

			#Clear Screen buffer
			clear

			if (( $TARGETMENUID == 0 )); then

				Menu_Main

			fi

		done

	#-----------------------------------------------------------------------------------
	#Run
	elif (( $INPUT == 1 )); then

		Run_Lets_Encrypt

	fi

	#-----------------------------------------------------------------------------------
	exit
	#-----------------------------------------------------------------------------------
}