#!/usr/bin/env bash

################################################################################
#
# V A R I A B L E S
#
################################################################################

# Some creds
INFO_NAME="check_http_expect"
INFO_AUTHOR="Patrick Plocke <patrick@plocke.de>"
INFO_GPGKEY="0x28BF179F"
INFO_DATE="2021-07-16"
INFO_LICENSE="MIT"
INFO_VERSION="0.5"
# ADD Additional authors here
INFO_CO_AUTHOR1="Mathias Scherer <scherer.mat@gmail.com>"
INFO_CO_AUTHOR2="Sylvia van Os <sylvia@hackerchick.me>"
INFO_CO_AUTHOR3="Martin Drößler <m.droessler@handelsblattgroup.com>"


# Get the path
export PATH="$PATH:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin"

# Nagios error codes
EXIT_OK=0
EXIT_WARN=1
EXIT_ERR=2
EXIT_UNKNOWN=3

# defaults
useragent="Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.6) Gecko/20070725 Firefox/2.0.0.6"
searchStrings=()

################################################################################
#
# F U N C T I O N S
#
################################################################################

############################################################
# Program Functions
############################################################

# Check program requirements
# @output string  Parsed, failed requirements
# @return integer 0|3
check_requirements() {
	if ! command -v curl > /dev/null 2>&1; then
		printf "[Failed] 'curl' must be installed.\n"
		return $EXIT_UNKNOWN
	else
		printf "[OK] 'curl' is installed.\n"
		return $EXIT_OK
	fi
}

# Give some creds
# @output string  The creds.
# @return integer 0
print_version() {
	printf "Name:       %s\n" "${INFO_NAME}"
	printf "Version:    %s (%s)\n" "${INFO_VERSION}" "${INFO_DATE}"
	printf "Author:     %s (%s)\n" "${INFO_AUTHOR}" "${INFO_GPGKEY}"
	printf "Co-Authors: %s\n" "${INFO_CO_AUTHOR1}"
	printf "            %s\n" "${INFO_CO_AUTHOR2}"
	printf "            %s\n" "${INFO_CO_AUTHOR3}"
	printf "License:    %s\n" "${INFO_LICENSE}"
	return 0
}


# Usage
# @output string  The usage screen.
# @return integer 0
print_usage() {
	printf "Usage:  check_http_expect --url <url> --find <string> [--insecure] [--huser <user>] [--hpass <pass>] [--lurl <url>] [--cookie <data> [--cookie <data>]][--ldata <data> [--ldata <data>]]\n"
	printf "OR      %s --check\n" "${INFO_NAME}"
	printf "OR      %s --help\n" "${INFO_NAME}"
	printf "OR      %s --version\n\n" "${INFO_NAME}"
	return 0
}


# Help
# @output string  The help screen.
# @return integer 0
print_help() {

	# Show usage first
	print_usage

	# Show description
	printf "Check a website (behind .htacess and/or behind POST login) for\n"
	printf "an expected string or regex expression.\n\n"

	# Show defaults
	printf "  --url                  Target URL\n"
	printf "  --find                 Find string in source of Target URL ('grep -E'-style regex allowed)\n"
	printf "  --insecure             [optional] allow insecure SSL connections\n"
	printf "  --huser                [optional] htaccess username\n"
	printf "  --hpass                [optional] htaccess password\n"
	printf "  --lurl                 [optional] Url for POST login\n"
	printf "  --ldata                [optional] POST data (can be specified multiple times)\n"
	printf "  --cookie		 [optional] set cookies for request\n\n"

	printf "  --check                Check for program requirements.\n"
	printf "  --help                 Show this help\n"
	printf "  --version              Show version information.\n"
	return 0
}



################################################################################
#
# M A I N   E N T R Y   P O I N T
#
################################################################################

############################################################
# Check for --check, --help or --version arguments
############################################################
if [ "${1}" = "--check" ]; then
	if ! check_requirements; then
		exit $EXIT_UNKNOWN
	fi
	exit $EXIT_OK
fi
if [ "${1}" = "--help" ]; then
	print_help
	exit $EXIT_OK
fi
if [ "${1}" = "--version" ]; then
	print_version
	exit $EXIT_OK
fi

############################################################
# Check requirements
############################################################

if ! command -v curl > /dev/null 2>&1; then
	printf "[UNKNOWN] 'curl' is required\n"
	exit $EXIT_UNKNOWN
fi


############################################################
# Retrieve arguments
############################################################

while [ $# -gt 0  ]; do
	key=$1
	shift
	case $key in

		# Final target url
		--url)
			url="$1"
			shift
			;;

		# Post parameter
		--lurl)
			lurl="$1"
			shift
			;;
		--ldata)
			# Append multiple data fields
			if [ -z "$ldata" ]; then
				ldata="--data \"$1\""
			else
				ldata="${ldata} --data \"$1\""
			fi
			shift
			;;

		# Htaccess parameters
		--huser)
			huser="$1"
			shift
			;;
		--hpass)
			hpass="$1"
			shift
			;;

		# String to look for on final url
		--find)
			searchStrings+=("$1")
			shift
			;;
		# Cookies
		--cookie)
			if [ -z "$cookies" ]; then
				cookies="--cookie \"$1\""
			else
				cookies="${cookies} --cookie \"$1\""
			fi
			shift
			;;
		# Insecure
		--insecure)
			insecure="1"
			;;
		--ua)
			useragent="$1"
			shift 
			;;
		*)
			echo "Invalid argument: '${1}'"
			print_usage
			exit 1
			;;
	esac
done


############################################################
# Validate arguments
############################################################

if [ -z "$url" ]; then
	echo "Error, You must specify an Url."
	print_usage
	exit 1
fi

if [ "${#searchStrings[@]}" -eq 0 ]; then
	echo "Error, You must specify what you are looking for."
	print_usage
	exit 1
fi


############################################################
# Go Go Go!!!!
############################################################

# Add htacess parameters
if [ ! -z "$huser" ] || [ ! -z "$hpass" ]; then
	curl_args="--user-agent \"${useragent}\" --user \"${huser}:${hpass}\""
else
	curl_args="--user-agent \"${useragent}\""
fi

if [ ! -z "$insecure" ]; then
	curl_args="-k ${curl_args}"
fi

# Add cookies
if [ ! -z "$cookies" ]; then
	curl_args="${curl_args} ${cookies}"
fi

# Login required?
if [ ! -z "${lurl}" ]; then
	login="curl -s -i ${curl_args}"
	login="${login} --cookie     cookie.jar"
	login="${login} --cookie-jar cookie.jar"
	login="${login} --location"
	login="${login} ${ldata}"
	login="${login} ${lurl}"

	crawl="curl -s -i ${curl_args}"
	crawl="${crawl} --cookie     cookie.jar"
	crawl="${crawl} --cookie-jar cookie.jar"
	crawl="${crawl} --location"
	crawl="${crawl} ${url}"

	# No fucking idea why the login only works, when it is called twice??
	eval "${login}" > /dev/null
	eval "${login}" > /dev/null


	output="$(eval "${crawl}")"
	rm -f cookie.jar
else
	# Connect and curl
	crawl="curl -s -i ${curl_args} ${url}"
	output="$(eval "${crawl}")"
fi

# Split header and content
head="$(echo "${output}" | awk '{if($0=="\r")exit;print}')"
data="$(echo "${output}" | awk '{if(body)print;if($0=="\r")body=1}')"

http_status="$(echo "${head}" | head -n1)"
http_version="$(echo "${http_status}" | awk '{print $1}')"
http_code="$(echo "${http_status}" | awk '{print $2}')"
http_info="$(echo "${http_status}" | awk '{for (i=3; i<NF; i++) printf $i " "; print $NF}')"
http_server="$(echo "${head}" | head -n20 | grep -E '^Server:\s' | sed 's/^Server:\s//g')"

match=""
numberOfResults=0
matchingStringAmount=0
expectedMatches=${#searchStrings[@]}
i=0
while [ $i -lt "$expectedMatches" ]; do
		el=${searchStrings[$i]}
		number=$(echo "${data}" | grep -cE "${el}")
		match+="$(echo "${data}" | grep -E "${el}")"
		numberOfResults=$((numberOfResults + number))
		if [ "$number" -gt 0 ]; then
				matchingStringAmount=$((matchingStringAmount + 1))
		fi
		((i++))
done


if [ "${expectedMatches}" -eq ${matchingStringAmount} ]; then
	if [ "$number" = "1" ]; then
		printf "[OK] 1 match found for: \"%s\" | 'Results'=%d\n" "$(printf "%s\n" "${searchStrings[@]}")" "${numberOfResults}"
	else
		printf "[OK] %d matches found for: \"%s\" | 'Results'=%d\n" "${numberOfResults}" "$(printf "%s\n" "${searchStrings[@]}")" "${numberOfResults}"
	fi
	EXIT="$EXIT_OK"
elif [ ${matchingStringAmount} -gt 0 ]; then
		printf "[WARN] Not all matches found for: \"%s\" | 'Results'=%d but expected: %d\n" "$(printf "%s\n" "${searchStrings[@]}")" "${matchingStringAmount}" "${expectedMatches}"
	EXIT="$EXIT_WARN"
else 
	printf "[CRITICAL] No matches found for: \"%s\" | 'Results'=0\n" "$(printf "%s\n" "${searchStrings[@]}")"
	EXIT="$EXIT_ERR"
fi

# Extended Output
echo "Http version:  ${http_version}"
echo "Http code:     ${http_code}"
echo "Http info:     ${http_info}"
echo "Server:        ${http_server}"
echo "Url:           ${url}"
#echo "Post Data:     ${ldata}"
echo "Search:        $(printf "%s\n\t\t" "${searchStrings[@]}")"
echo "Num matches:   ${numberOfResults}"
echo "Matches:"
echo "----------------------------------------"
echo "${match}"

exit "$EXIT"
