#!/bin/bash

# righthand script
# Used to wrap custom operations inside one script
#

########################## RH user defined functions ###########################

# all user defined operation starts with "rh_op_" prefix.


### Utility functions

go_root_dir()
{
	if ! [ -z $ULY_WD ]
	then
		cd $ULY_WD/..
	fi

	cd $(dirname $(readlink -f "$0"))
	cd ..
}

go_root_dir_env()
{
	if ! [ -z $ULY_WD ]
	then
		cd $ULY_WD/..
	fi

	go_root_dir
	if [ ! -f infrastructure.envsh ]
	then
		echo "infrastructure.envsh does not exists in the project root directory. Use infrastructure.envsh to configure one."
		exit 1
	fi
	source infrastructure.envsh
}

uly_gen_envpairs()
{
	for m in ${ULY_VARS//,/ }
	do
		if [ ! -z $OPT ]
		then
			echo $OPT
		fi
		echo "$1""$m=${!m}"
	done
}

dc_fireup()
{
	docker-compose build $(OPT="--build-arg"; uly_gen_envpairs)
	docker-compose up -d
}

ensure_ca_init()
{
	go_root_dir_env
	cd WD
	if ! [ -d "CA" ]; then
		echo "Infrastructure CA not created yet. Creating new CA... "
		mkdir CA && cd CA

		echo "password" > mypass.enc

	  # generate CA private key
		openssl genrsa -des3 -passout file:mypass.enc -out ca.key 4096

		#check:
		#openssl rsa -noout -text -in ca.key -passin file:mypass.enc

	  # Generate CA Cert
		openssl req -new -x509 -days 36500 -key ca.key -out ca.cert.pem -passin file:mypass.enc \
			-addext "keyUsage                = critical, cRLSign, digitalSignature, keyCertSign" \
			-subj "/C=HU/ST=Hungary/L=Budapest/O=ULYSYS/OU=KFT/CN=ulysys/emailAddress=ulysys@dankodavid.hu/"
	fi
}

############################ Env utility operations ############################

rh_op_test()
{
		dc_fireup
}

rh_op_env_launch()
{
	_rh_try_ret_help "Executes and enters the launch environment"
	go_root_dir_env
	exec bash
}

rh_op_env_print()
{
	_rh_try_ret_help "Prints all launch environment variable"
	go_root_dir_env
	export
}

rh_op_dc_fireup()
{
	_rh_try_ret_help "Runs \`docker-composer\` build with all env variable supplied with --build-arg; then runs \`docker-composer up -d\`"
	dc_fireup
}

rh_op_ensure_certificate()
{
		_rh_try_ret_help "Ensure certificate is created under ./WD/CA"

		ensure_ca_init
		go_root_dir_env
		cd WD/CA

		if [ -z $1 ]
		then
			echo "No server name given"
			exit 1
		fi

		if [ -f "$1.key" ]
		then
			echo "$1.key already exists"
			exit 1
		fi

		if [ ! -f "ca.key" ]
		then
			echo "ca.key doesnot exists, call ensure_ca_init to initialize CA"
			exit 1
		fi

SRV=$1
FQDN=$1


cat > v3.ext <<- EOF

##Required
[ req ]
default_bits                                         = 4096
distinguished_name                           = req_distinguished_name

##About the system for the request. Ensure the CN = FQDN
[ req_distinguished_name ]
commonName                                    = $FQDN

##Extensions to add to a certificate request for how it will be used

[v3_ca]
basicConstraints=CA:FALSE
nsCertType                      = client, server, email
extendedKeyUsage = serverAuth, clientAuth, codeSigning, emailProtection
nsComment                       = "OpenSSL Generated Certificate"
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
authorityInfoAccess=OCSP;URI:http://ocsp.my.host/
certificatePolicies= 1.2.4.5, 1.1.3.4


keyUsage = critical,digitalSignature, keyEncipherment
subjectAltName = DNS:$FQDN, DNS:*.$FQDN

EOF

	# Generate client
	#key
	openssl genrsa -des3 -passout file:mypass.enc -out $SRV.key 4096
	# gen cert Request
	openssl req -new -key $SRV.key -out $SRV.csr -passin file:mypass.enc -subj "/CN=$FQDN/" -config v3.ext -extensions v3_ca

	# verify
	# openssl rsa -noout -text -in server.key -passin file:mypass.enc


	# sign the key
	openssl x509 -req -days 36500 -in $SRV.csr -CA ca.cert.pem -extfile v3.ext -CAkey ca.key -CAcreateserial -out $SRV.signed -passin file:mypass.enc -extensions v3_ca -extfile ./v3.ext


	rm v3.ext


	# verify
	#openssl x509 -noout -text -in server.crt

	# verify signed
	# openssl verify -CAfile ca.cert.pem server.crt

	# remove password
	openssl rsa -in $SRV.key -out $SRV.keypassless -passin file:mypass.enc

	#fullchain generálása
	cat $SRV.signed ca.cert.pem > $SRV.fullchain.pem


	#In apache configuration use:
	#SSLCertificateFile	$(readlink -f $SRV.fullchain.pem)
	#SSLCertificateKeyFile	$(readlink -f $SRV.keypassless)
	#EOF
}

rh_op_docker_install_certificate()
{
	_rh_try_ret_help "Installs the specified cerficate on the host system. After this, you need to restart docker"
	go_root_dir_env
	SRC=WD/CA/$1.signed
	if ! [ -f $SRC ]; then
		echo "Certificate does not exists $SRC"
		exit 1
	fi

	TO=/etc/docker/certs.d/$1.crt
	if [ -f $TO ]; then
		echo "Certificate already imported to "$TO", if you want to reinstall run this before trying again:"
		echo "rm $TO"
		exit 1
	fi

	cp $FROM $TO
	echo "You need to restart docker to take the action effect:"
	echo "service docker restart"
}

rh_op_register_ca()
{
	_rh_try_ret_help "(DEPRECATED, use docker_install_certificate instead) Registers the generated certificate authority as ROOT CA on the current system."
	ensure_ca_init
	go_root_dir_env

	mkdir -p /usr/share/ca-certificates/custom/
	cp WD/CA/ca.cert.pem /usr/share/ca-certificates/custom/ulysys.ca.crt
	if ! grep -q "custom/ulysys.ca.crt" /etc/ca-certificates.conf
	then
		echo "custom/ulysys.ca.crt" >> /etc/ca-certificates.conf
	fi
	update-ca-certificates
}

#TODO remove CA

########################## Infrastructure operations ###########################

ULY_INFRASTRUCTURES=("repo" "gitlab" "registry")

rh_op_infra_op()
{
	_rh_try_ret_help "Executes operation on infrastucture element like: start|stop|restart|purge|cycle"
	go_root_dir_env
	cd infrastructures
	cd $1
	case $2 in
		start)
			if [ -f init.sh ]
			then
				./init.sh
			fi
			dc_fireup
		;;

		stop)
			docker-compose down
		;;

		purge)
			docker-compose rm -vsf
		;;

		restart)
			rh_op_infra_op $1 stop
			rh_op_infra_op $1 start
		;;

		cycle)
			rh_op_infra_op $1 stop
			rh_op_infra_op $1 purge
			rh_op_infra_op $1 start
		;;

		 *)
		 echo "Invalid operation $2 usage: \$INFRASTRUCTURE_NAME, {start|stop|purge|cycle}"
		 ;;
	esac
}

_op_infra_all()
{
	for inf in "${@:2}"
	do
		rh_op_infra_op $inf $1
	done
}



rh_op_infrastructures_start()
{
	_rh_try_ret_help "Starts all infrastructures located in ./infrastructures directory"
	_op_infra_all start ${ULY_INFRASTRUCTURES[@]}
}


rh_op_infrastructures_stop()
{
	_rh_try_ret_help "Stops all infrastructures located in ./infrastructures directory"
	_op_infra_all stop ${ULY_INFRASTRUCTURES[@]}
}

rh_op_infrastructures_restart()
{
	_rh_try_ret_help "Restarts all infrastructures located in ./infrastructures directory"
	_op_infra_all stop ${ULY_INFRASTRUCTURES[@]}
	_op_infra_all start ${ULY_INFRASTRUCTURES[@]}
}


rh_op_infrastructures_purge()
(
	_rh_try_ret_help "Purge all infrastructure like it was never on your computer"
	_op_infra_all purge ${ULY_INFRASTRUCTURES[@]}
)

rh_op_infrastructures_cycle()
{
	_rh_try_ret_help "Stops, Purge, Starts all infrastructures"
	set -e
	rh_op_infrastructures_stop
	rh_op_infrastructures_purge
	rh_op_infrastructures_start
}



############################## Gitlab operations ###############################

rh_op_gitlab_reset_password()
{
	_rh_try_ret_help "Attach to the running gitlab container and starts a password reset prompt"
	echo "Note: password must be at least 8 character long, root user is always registered"
	echo "Waiting prompt to appear (it might take some time)..."
	docker exec -it gitlab-ce gitlab-rake "gitlab:password:reset"
}

rh_op_gitlab_wait_start()
{
	_rh_try_ret_help "Block the shell until gitlab gets available"
	go_root_dir_env

	while ! wget "http://127.0.0.1:$GITLAB_EXPORT_WEB_PORT/" -O - > /dev/null 2>&1
	do
		echo "Retry"
		sleep 1
	done

	if [ "$1" "=" "gui" ]
	then
		zenity --info --text "Gitlab become available. Press OK to continue."
	fi
}

rh_op_gitlab_run_phase_here()
{
	_rh_try_ret_help "Assuming you run this in a project's directory it runs the gitlab runner with the specified phase"
	gitlab-runner exec shell $1
}

################################################################################
############################# RH helper functions ##############################
################################################################################

_rh_try_ret_help()
{
	if [ ! -z $RH_RUNTIME_REQUEST_HELP ]
	then
		echo $1
		exit 1;
	fi
}

_rh_get_universe_name()
{
	if [ ! -z $RH_UNIVERSE_NAME ]
	then
		echo "$RH_UNIVERSE_NAME"
	elif [ -f "$(dirname $0)/.rh_universe_name" ]
	then
		cat "$(dirname $0)/.rh_universe_name"
	else
		echo $(dirname $(readlink -f "$0")) | grep -Po "[^/]+$"
	fi
}

############################ RH built-in functions #############################

rh_op_enter()
{
	_rh_try_ret_help 'Executes new bash shell that include rh command and all neighbor scripts ($PATH injection).'

	export PS1="RH("$(_rh_get_universe_name)"): $(bash -i -c 'echo $PS1') "
	export PATH="$PATH:"$(dirname $(readlink -f "$0"))
	EX="export PS1="$(printf "%q" "$PS1")";"
	EX+="complete -W \"${RH_FUNCTIONS[@]}\" 'rh';"
	exec /bin/bash --init-file <(echo "$EX")
}

rh_op_echo()
{
	_rh_try_ret_help "Test command, echoes back every argument"
	echo "echo in RH: $@"
}

rh_op_help()
{
	_rh_try_ret_help "Returns RH help with the list of all defined functions"

	echo "RH stands for 'right hand'. It is a wrapper script wherein you can collect tiny commands."
	echo "Specify one righthand function from the followings:"

	RH_RUNTIME_REQUEST_HELP=true

	for f in ${RH_FUNCTIONS[@]}
	do
		# if the command has help
		if type "rh_op_"$f | grep -q _rh_try_ret_help
		then
			echo -e "\t$f - "$("rh_op_"$f)
		else
			echo -e "\t$f"
		fi
	done
}

rh_op_print_universe()
{
	_rh_try_ret_help 'Prints the logical name of the RH command repository. You can change by specifying $RH_UNIVERSE_NAME or editing the content of the rh command neighbor file .rh_universe_name'
	echo $(_rh_get_universe_name)
}

############################## Application area ################################

# Collection available commands
RH_FUNCTIONS=()

for func in `declare -F | grep -Po '(?<=rh_op_).*$' | sort`
do
	RH_FUNCTIONS+=($func);
done

# print help if nothing specified

if [ $# '<' '1' ]
then
	rh_op_help
	exit 1
fi

# run command
for f in ${RH_FUNCTIONS[@]}
do
	if [ "$1" "=" "$f" ]
	then
		"rh_op_"$f "${@:2}"
		exit $?
	fi
done

echo "Righthand function $1 not found, so now printing help..."
rh_op_help
exit 1
