#!/usr/bin/env bash
set -Eeuo pipefail
declare catalog san
catalog="$(mktemp)"
san="$(mktemp)"
readonly catalog san
declare invalid=0
openstack catalog list --format json --column Name --column Endpoints \
	| jq -r '.[] | .Name as $name | .Endpoints[] | select(.interface=="public") | [$name, .interface, .url] | join(" ")' \
	| sort \
	> "$catalog"
while read -r name interface url; do
	# Ignore HTTP
	if [[ ${url#"http://"} != "$url" ]]; then
		continue
	fi
	# Remove the schema from the URL
	noschema=${url#"https://"}
	# If the schema was not HTTPS, error
	if [[ "$noschema" == "$url" ]]; then
		echo "ERROR (unknown schema): $name $interface $url"
		exit 2
	fi
	# Remove the path and only keep host and port
	noschema="${noschema%%/*}"
	host="${noschema%%:*}"
	port="${noschema##*:}"
	# Add the port if was implicit
	if [[ "$port" == "$host" ]]; then
		port='443'
	fi
	# Get the SAN fields
	openssl s_client -showcerts -servername "$host" -connect "$host:$port" </dev/null 2>/dev/null \
		| openssl x509 -noout -ext subjectAltName \
		> "$san"
	# openssl returns the empty string if no SAN is found.
	# If a SAN is found, openssl is expected to return something like:
	#
	#    X509v3 Subject Alternative Name:
	#        DNS:standalone, DNS:osp1, IP Address:192.168.2.1, IP Address:10.254.1.2
	if [[ "$(grep -c "Subject Alternative Name" "$san" || true)" -gt 0 ]]; then
		echo "PASS: $name $interface $url"
	else
		invalid=$((invalid+1))
		echo "INVALID: $name $interface $url"
	fi
done < "$catalog"
# clean up temporary files
rm "$catalog" "$san"
if [[ $invalid -gt 0 ]]; then
	echo "${invalid} legacy certificates were detected. Update your certificates to include a SAN field."
	exit 1
else
	echo "All HTTPS certificates for this cloud are valid."
fi