#!/bin/sh
#
# Purpose {{{
# This script will display SSL dates of a given URL
#   1. …
# …
#
# 2021-12-06
# }}}
# Vars {{{
readonly PROGNAME=$(basename "${0}")
readonly PROGDIR=$(readlink -m $(dirname "${0}"))
readonly ARGS="${*}"
readonly NBARGS="${#}"
[ -z "${DEBUG}" ] && DEBUG=1
## Export DEBUG for sub-script
export DEBUG

# Default values for some vars
readonly MY_VAR_XY_DEFAULT="666"

## Colors
readonly PURPLE='\033[1;35m'
readonly RED='\033[0;31m'
readonly RESET='\033[0m'
readonly COLOR_DEBUG="${PURPLE}"
# }}}
usage() {                                                       # {{{

	cat <<- EOF
usage: $PROGNAME [-d|-h] -f /urls/list/path|-u URL

Try to get SSL's date (notBefore and notAfter) from URL(s).

EXAMPLES :
    - Get dates for wikipedia.org's SSL cert
        ${PROGNAME} --url wikipedia.org

    - Get SSL dates for all URLs of the given file
        ${PROGNAME} --file /tmp/ssl.url.list

OPTIONS :
    -d,--debug
        Enable debug messages.

    -f,--file
        Specify the file with URLs to verify.

    -h,--help
        Print this help message.

    -u,--url
        Specify the URL to verify.

	EOF

}
# }}}
debug_message() {                                               # {{{

	local_message="${1}"

	## Print message if DEBUG is enable (=0)
	[ "${DEBUG}" -eq "0" ] && printf '\e[1;35m%-6b\e[m\n' "DEBUG − ${PROGNAME} : ${local_message}"

	return 0
}
# }}}
error_message() {                                               # {{{

	local_error_message="${1}"
	local_error_code="${2}"

	## Print message if DEBUG is enable (=0)
	[ "${DEBUG}" -eq "0" ] && printf '%b\n' "ERROR − ${PROGNAME} : ${RED}${local_error_message}${RESET}"

	exit "${local_error_code:=66}"
}
# }}}
define_vars() {                                                 # {{{

	## If my_var_xy wasn't defined (argument) {{{
	if [ -z "${my_var_xy}" ]; then
		## Use default value
		readonly my_var_xy="${MY_VAR_XY_DEFAULT}"
	fi
	## }}}

}
# }}}
is_var_defined() {                                            # {{{

	local_var_defined="${1}"

	## Return an error by default
	return_is_var_defined="1"

	## If the length of the variable is nonzero
	if [ -n "${local_var_defined}" ]; then
		debug_message "is_var_defined − \
Variable ${RED}is defined${COLOR_DEBUG} and not empty."
		return_is_var_defined="0"
	else
		debug_message "is_var_defined − \
Var is ${RED}not${COLOR_DEBUG} defined or empty."
		return_is_var_defined="1"
	fi

	return "${return_is_var_defined}"

}
# }}}
is_file_present() {                                             # {{{

	local_file_present="${1}"

	## File doesn't exist by default
	return_is_file_present="1"

	### Check if the file exists
	# shellcheck disable=SC2086
	if find ${local_file_present} > /dev/null 2>&1; then
		return_is_file_present="0"
		debug_message "is_file_present − \
The file ${RED}${local_file_present}${COLOR_DEBUG} exists."
	else
		return_is_file_present="1"
		debug_message "is_file_present − \
The file ${RED}${local_file_present}${COLOR_DEBUG} doesn't exist."
	fi

	return "${return_is_file_present}"

}
# }}}
display_url_date() {                                            # {{{

	local_ssl_url="${1}"

	## Return an error by default
	return_display_url_date="1"

	if echo | openssl s_client -servername "${local_ssl_url}" -connect "${local_ssl_url}":443 2>/dev/null \
	| openssl x509 > /dev/null 2>&1 ; then
		debug_message "display_url_date − \
Successfully got SSL's dates from ${RED}${local_ssl_url}${COLOR_DEBUG} URL."
		### Display SSL's dates
		echo | openssl s_client -servername "${local_ssl_url}" -connect "${local_ssl_url}":443 2>/dev/null | openssl x509 -noout -dates
		return_display_url_date="0"
	else
		debug_message "display_url_date − \
Error with 'openssl' command for ${RED}${local_ssl_url}${COLOR_DEBUG}."
		return_display_url_date="1"
	fi

	return "${return_display_url_date}"

}
# }}}

main() {                                                        # {{{

	## If script should not be executed right now {{{
	### Exit
	#is_script_ok \
		#&& exit 0
	## }}}

	## Define all vars
	define_vars

	## If an URL was given as argument {{{
	### Display the URL
	### AND Try to get SSL's dates
	### AND exit
	is_var_defined "${ssl_url}" \
		&& printf '%b\n' "Try to get SSL dates for ${RED}${ssl_url}${RESET} URL :" \
		&& display_url_date "${ssl_url}" \
		&& exit 0
	## }}}
	## If a file was given as argument {{{
	### Display the URL
	### AND Try to get SSL's dates
	### AND exit
	is_var_defined "${ssl_url_list_path}" \
		&& is_file_present "${ssl_url_list_path}" \
		&& printf '%b\n' "Try to manage URLs from ${RED}${ssl_url_list_path}${RESET} file :" \
		&& while IFS= read -r url; do
			printf '%b\n' "Try to get SSL dates for ${RED}${url}${RESET} URL :"
			display_url_date "${url}"
		done < "${ssl_url_list_path}" \
		&& exit 0
	## }}}

	## Display help message {{{
	### AND exit with error
	usage \
		&& error_message "Please use at least -f or -u argument to give a file or an URL. See help message." 1
	## }}}

}
# }}}

# Manage arguments                                                # {{{
# This code can't be in a function due to argument management

if [ ! "${NBARGS}" -eq "0" ]; then

	manage_arg="0"

	## If the first argument is not an option
	if ! printf -- '%s' "${1}" | grep -q -E -- "^-+";
	then
		## Print help message and exit
		printf '%b\n' "${RED}Invalid option: ${1}${RESET}"
		printf '%b\n' "---"
		usage

		exit 1
	fi

	# Parse all options (start with a "-") one by one
	while printf -- '%s' "${1}" | grep -q -E -- "^-+"; do

	case "${1}" in
		-d|--debug )                          ## debug
			DEBUG=0
			;;
		-h|--help )                           ## help
			usage
			## Exit after help informations
			exit 0
			;;
		-f|--file )                           ## Define ssl_url_list_path with given arg
			## Move to the next argument
			shift
			## Define var
			readonly ssl_url_list_path="${1}"
			;;
		-u|--url )                            ## Define ssl_url with given arg
			## Move to the next argument
			shift
			## Define var
			readonly ssl_url="${1}"
			;;
		* )                                   ## unknow option
			printf '%b\n' "${RED}Invalid option: ${1}${RESET}"
			printf '%b\n' "---"
			usage
			exit 1
			;;
	esac

	debug_message "Arguments management − \
${RED}${1}${COLOR_DEBUG} option managed."

	## Move to the next argument
	shift
	manage_arg=$((manage_arg+1))

	done

	debug_message "Arguments management − \
${RED}${manage_arg}${COLOR_DEBUG} argument(s) successfully managed."
else
	debug_message "Arguments management − \
No arguments/options to manage."
fi

# }}}

main

exit 255