#!/bin/bash



#  This script installs Apache Guacamole server/client and Tomcat on Debian 12 and enables them to start automatically.
#  It's intended to be run as root on a fresh Debian 12 Linux container.
#
#  This script acts as a very quick method to set up a Guacamole server which is only suitable for personal use or testing.
#  It's intended to be changed for anyone's specific use case, and should only be treated as a starting point.
#  Please read the entirety of this script before using it.
#
#
#  Tomcat is installed to the /opt/tomcatX directory, where X is the main version number.
#  Tomcat Logs are in /opt/tomcatX/logs.
#  Guacamole configuration files are located in /etc/guacamole.
#
#  The web interface can be accessed at http://<local IP>:8080/guacamole
#  The default credentials are "guacadmin" for username and password.



# Versions other than the defaults have not been tested.
# Guacamole 1.5.5 is incompatible with Tomcat 10.
# Older versions may require downloading from the Apache archive.
GUAC=1.5.5
TOMCAT=9
TOMCATVER=9.0.93
# Java installation uses the OpenJDK JRE Headless package.
# Older Java versions may not be available from system repositories.
JAVA=17

# Remove delays after messages by setting these to zero.
WAITLONG=2
WAIT=1
WAITSHORT=0.5

# You can set passwords in advance here if you don't want to be prompted.
MARIADBPASS=''
GUACUSERPASS=''



timer() {
	sleep 0.5
	for time in 4 . . . 3 . . . 2 . . . 1 . . . ; do
		printf "$time"; sleep 0.25; done
}

skipSection() {
	while true; do
		IFS=
		printf "$@"
		read -rs -t 4.5 -n 1 key || key=Y
		kill $! 2>/dev/null
		case $key in
			'Y'|'y'|' ' )
				printf " starting.\n";
				return 0;;
			'N'|'n'|$'\t' )
				printf " skipping.\n"; sleep $WAITSHORT
				return 1;;
			'Q'|'q'|$'\e' )
				printf " exiting.\n"; sleep $WAITSHORT
				exit 0;;
			* )
				printf " invalid input.\n"; sleep $WAITSHORT
				timer &;;
		esac
	done
}

downloadError() {
	printf " -> [ERROR] Error downloading.\n"; $WAITSHORT
	printf " -> Exiting.\n"; exit 1; }
installError() {
	printf " -> [ERROR] Error installing packages.\n"; $WAITSHORT
	printf " -> Exiting.\n"; exit 1; }
updateError() {
	printf " -> [ERROR] Error updating.\n"; $WAITSHORT
	printf " -> Exiting.\n"; exit 1; }



printf "\n=> [INFO] The following keys can be pressed during timers.\n"
printf " -> SPACE or Y starts that step.\n"
printf " -> TAB or N skips that step.\n"
printf " -> ESC or Q exits the script.\n"
sleep $WAITLONG

printf "\n"; timer &
skipSection "=> Starting in: "
sleep $WAITSHORT



printf "\n"; timer &
skipSection "=> Running system updates in: " && {
	printf " -> Updating repositories.\n"; sleep $WAITSHORT
	apt update -y || updateError

	printf " -> Upgrading system.\n"; sleep $WAITSHORT
	apt full-upgrade -y || updateError

	printf " -> Finished running system updates.\n"
	sleep $WAIT
}



printf "\n"; timer &
skipSection "=> Installing Guacamole $GUAC server in: " && {
	printf " -> Installing dependencies.\n"; sleep $WAITSHORT
	apt install -y libcairo2-dev libjpeg62-turbo-dev libpng-dev libtool-bin uuid-dev freerdp2-dev libpango1.0-dev libssh2-1-dev libvncserver-dev libpulse-dev libssl-dev libvorbis-dev libwebp-dev build-essential || installError
	# Add 'libavcodec-dev libavformat-dev libavutil-dev libswscale-dev' to record guacamole sessions.
	# Add 'libtelnet-dev' for Telnet support.
	# Add 'libwebsockets-dev' for Kubernetes support.

	printf " -> Downloading Guacamole $GUAC server.\n"; sleep $WAITSHORT
	wget https://dlcdn.apache.org/guacamole/$GUAC/source/guacamole-server-$GUAC.tar.gz -O guacamole-server-$GUAC.tar.gz || downloadError
	# Note that the Guacamole downloader uses the dlcdn.apache.org mirror, which doesn't include older releases.
	# Older releases can be found from archive.apache.org:
	#    https://archive.apache.org/dist/guacamole/$GUAC/source/guacamole-server-$GUAC.tar.gz

	printf " -> Setting up server.\n"; sleep $WAITSHORT
	tar -xzf guacamole-server-$GUAC.tar.gz
	cd guacamole-server-$GUAC/

	printf " -> Configuring.\n"; sleep $WAITSHORT
	./configure --with-systemd-dir=/etc/systemd/system/

	printf " -> Installing server.\n"; sleep $WAITSHORT
	make
	make install

	printf " -> Updating installed libraries cache.\n"; sleep $WAITSHORT
	ldconfig
	cd ..

	printf " -> Enabling systemd unit.\n"; sleep $WAITSHORT
	systemctl daemon-reload
	systemctl enable guacd.service

	timer &
	skipSection " -> Starting server in: " && {
		systemctl start guacd.service
	}

	printf " -> Finished installing Guacamole $GUAC server.\n"
	sleep $WAIT
}




printf "\n"; timer &
skipSection "=> Installing Tomcat $TOMCAT in: " && {
	printf " -> Installing dependencies.\n"; sleep $WAITSHORT
	apt install -y openjdk-$JAVA-jdk-headless || installError

	printf " -> Downloading Tomcat $TOMCAT.\n"; sleep $WAITSHORT
	wget https://dlcdn.apache.org/tomcat/tomcat-$TOMCAT/v$TOMCATVER/bin/apache-tomcat-$TOMCATVER.tar.gz -O apache-tomcat-$TOMCATVER.tar.gz || downloadError
	# Note that the Tomcat downloader uses the dlcdn.apache.org mirror, which doesn't include older releases.
	# Older releases can be found from archive.apache.org:
	#    https://archive.apache.org/dist/tomcat/tomcat-$TOMCAT/v$TOMCATVER/bin/apache-tomcat-$TOMCATVER.tar.gz

	printf " -> Setting up.\n"; sleep $WAITSHORT
	tar -xzf apache-tomcat-$TOMCATVER.tar.gz
	mv apache-tomcat-$TOMCATVER /opt/tomcat$TOMCAT

	printf " -> Creating tomcat user.\n"; sleep $WAITSHORT
	useradd -r -m -s /bin/bash tomcat
	chown -R tomcat:tomcat /opt/tomcat$TOMCAT

	printf " -> Creating systemd unit files.\n"; sleep $WAITSHORT

	cat > /etc/systemd/system/tomcat$TOMCAT.service <<- EOF
		[Unit]
		Description=Apache Tomcat $TOMCAT
		After=network.target

		[Service]
		Type=forking

		User=tomcat
		Group=tomcat
		Environment="CATALINA_HOME=/opt/tomcat$TOMCAT"
		ExecStart=/opt/tomcat$TOMCAT/bin/startup.sh
		ExecStop=/opt/tomcat$TOMCAT/bin/shutdown.sh
		Restart=on-failure

		[Install]
		WantedBy=multi-user.target
	EOF

	printf " -> Enabling systemd unit.\n"; sleep $WAITSHORT
	systemctl daemon-reload
	systemctl enable tomcat$TOMCAT.service

	timer &
	skipSection " -> Starting server in: " && {
		systemctl start tomcat$TOMCAT.service
	}

	printf " -> Finished installing Tomcat $TOMCAT.\n"
	sleep $WAIT
}



printf "\n"; timer &
skipSection "=> Installing Guacamole $GUAC client in: " && {
	printf " -> Downloading Guacamole $GUAC client.\n"; sleep $WAITSHORT
	wget https://dlcdn.apache.org/guacamole/$GUAC/binary/guacamole-$GUAC.war -O guacamole-$GUAC.war || downloadError
	# Note that the Guacamole downloader uses the dlcdn.apache.org mirror, which doesn't include older releases.
	# Older releases can be found from archive.apache.org:
	#    https://archive.apache.org/dist/guacamole/$GUAC/binary/guacamole-$GUAC.war

	printf " -> Setting up client.\n"; sleep $WAITSHORT
	cp guacamole-$GUAC.war /opt/tomcat$TOMCAT/webapps/guacamole.war

	printf " -> Creating configuration directories.\n"; sleep $WAITSHORT
	mkdir /etc/guacamole
	ln -s /etc/guacamole/ /opt/tomcat$TOMCAT/.guacamole
	mkdir /etc/guacamole/{extensions,lib}

	printf " -> Finished installing Guacamole $GUAC client.\n"
	sleep $WAIT
}

printf "\n"; timer &
skipSection "=> Setting up Guacamole configuration files in: " && {
	printf " -> Creating guacamole.properties.\n"; sleep $WAITSHORT

	cat > /etc/guacamole/guacamole.properties <<- EOF
		# Hostname and port of guacamole proxy
		guacd-hostname: localhost
		guacd-port:     4822
		# MariaDB properties
		mysql-hostname: localhost
		mysql-database: guacamole_db
		mysql-username: guacdb_admin
	EOF
# mysql-driver and mysql-password is appended during database setup

	printf " -> Creating guacd.conf.\n"; sleep $WAITSHORT

	cat > /etc/guacamole/guacd.conf <<- EOF
		[server]
		bind_host = 127.0.0.1
		bind_port = 4822
	EOF

#    printf " -> Creating user-mapping.xml.\n"; sleep $WAITSHORT
#
#cat > /etc/guacamole/user-mapping.xml << EOF
#<user-mapping>
#    <authorize 
#            username="guacadmin"
#            password="5cbd438413e8e3ca0e14e200fde621a9"
#            encoding="md5">
#
#        <connection name="Example 1">
#            <protocol>ssh</protocol>
#            <param name="hostname">192.168.4.87</param>
#            <param name="port">22</param>
#        </connection>
#
#        <connection name="Example 2">
#            <protocol>ssh</protocol>
#            <param name="hostname">10.1.0.8</param>
#            <param name="port">22</param>
#        </connection>
#
#    </authorize>
#</user-mapping>
#EOF

	printf " -> Finished setting up Guacamole configuration files.\n"
	sleep $WAIT
}



printf "\n"; timer &
skipSection "=> Installing authentication database in: " && {
	printf " -> Installing MariaDB.\n"; sleep $WAITSHORT
	apt install -y mariadb-server || installError

	printf " -> Downloading database authentication extension.\n"; sleep $WAITSHORT
	wget https://dlcdn.apache.org/guacamole/$GUAC/binary/guacamole-auth-jdbc-$GUAC.tar.gz -O guacamole-auth-jdbc-$GUAC.tar.gz || downloadError
	# Note that the Guacamole downloader uses the dlcdn.apache.org mirror, which doesn't include older releases.
	# Older releases can be found from archive.apache.org:
	#    https://archive.apache.org/dist/guacamole/$GUAC/binary/guacamole-auth-jdbc-$GUAC.tar.gz

	printf " -> Installing extension.\n"; sleep $WAITSHORT
	tar -xzf guacamole-auth-jdbc-$GUAC.tar.gz
	cp guacamole-auth-jdbc-$GUAC/mysql/guacamole-auth-jdbc-mysql-$GUAC.jar /etc/guacamole/extensions/

	printf " -> Downloading MySQL JDBC driver.\n"; sleep $WAITSHORT
	wget https://dev.mysql.com/get/Downloads/Connector-J/mysql-connector-j-9.0.0.tar.gz -O mysql-connector-j-9.0.0.tar.gz || downloadError
	# This may need to be changed for other versions.
	# 'No suitable driver found' error when using MariaDB connector.

	printf " -> Installing JDBC driver.\n"; sleep $WAITSHORT
	tar -xzf mysql-connector-j-9.0.0.tar.gz
	cp mysql-connector-j-9.0.0/mysql-connector-j-9.0.0.jar /etc/guacamole/lib/

	printf "   -> Appending driver to guacamole.properties.\n"; sleep $WAITSHORT
	printf "mysql-driver: mysql\n" >> /etc/guacamole/guacamole.properties

	printf " -> Setting up database.\n"; sleep $WAITSHORT
	if [ "$MARIADBPASS" = '' ]; then
		read -rs -p "   -> Enter database guacamole_db password: " MARIADBPASS
		printf "\n"
	fi
	mariadb -u root -p"$MARIADBPASS" -e "CREATE DATABASE guacamole_db;"

	printf "   -> Copying data.\n"; sleep $WAITSHORT
	cat guacamole-auth-jdbc-$GUAC/mysql/schema/*.sql | mariadb -u root -p"$MARIADBPASS" guacamole_db

	if [ "$GUACUSERPASS" = '' ]; then
		read -rs -p "   -> Enter guacdb_admin password: " GUACUSERPASS
		printf "\n"
	fi
	mariadb -u root -p"$MARIADBPASS" -e "
		CREATE USER 'guacdb_admin'@'localhost' IDENTIFIED BY '$GUACUSERPASS';
		GRANT SELECT,INSERT,UPDATE,DELETE ON guacamole_db.* TO 'guacdb_admin'@'localhost';
		FLUSH PRIVILEGES;"

	printf "   -> Appending database password to guacamole.properties.\n"; sleep $WAITSHORT
	printf "mysql-password: $MARIADBPASS\n" >> /etc/guacamole/guacamole.properties

	printf " -> Finished setting up authentication database.\n"
	sleep $WAIT
}



printf "\n"; timer &
skipSection "=> Restarting services in: " && {
	printf "   -> Restarting.\n"; sleep $WAITSHORT
	systemctl restart tomcat$TOMCAT.service guacd.service
}

printf "=> Installation complete.\n"; sleep $WAITSHORT