#!/bin/bash
#
# StackX SSL 
# sxssl.sh 
#
# Author: Christophe Casalegno / Brain 0verride
# Contact: brain@christophe-casalegno.com
# Version 0.2
#
# Copyright (c) 2020 Christophe Casalegno
# 
# This program is free software: you can redistribute it and/or modify
#
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <https://www.gnu.org/licenses/>
#
# The license is available on this server here: 
# https://www.christophe-casalegno.com/licences/gpl-3.0.txt
#
# Usage: 
# cp sxssl.sh /usr/local/bin/sxssl
# chmod +x /usr/local/bin/sxssl
# sxssl <fqdn> or <fqdn1,fqdn2,fqdn3,...>
#
# Don't forget to setup email & ip
# email="youremail@address"
# ip="<ip> or <ip1,ip2,ip3,...>
# ip can be IPv4 or IPv6 and can be mixed
#
# Working fine on StackX for Debian 10, 11 & 12

fqdns=$1 # We retrieve the first parameter passed to the script
expand=$2 # We retrieve the second parameter passed to the script to check if it's a simple addition to an existing certificate.

email="brain@christophe-casalegno.com" # Email address passed to Certbot which will receive information about the domain (renewal issues, etc.)
ip="192.168.0.1" # Address or list of valid IPv4 and IPv6 addresses, comma-separated, for which the certificate is accepted to be generated
sslok="1" # By default, if not contradicted by a test, the certificate generation will proceed

# We define a set of colors for clearer display

RED='\033[38;5;160m' #ex echo -e "${RED} ALERT"
NC='\033[0m'             #ex echo -e "${NC} Normal"
GREEN='\033[38;1;32m'    #ex echo -e "${GREEN} OK"

IFS=',' read -ra FQDNS <<< "$fqdns" # On définit la virgule comme séparateur pour le tableau FQDNS
IFS=',' read -ra IPS <<< "$ip" # On définit la virgule comme séparateur pour le tableau IPS

# We now check whether the arguments passed to the script exist, and if so, whether they meet our expectations and follow the format of a valid FQDN

print_line() # Display a separator line for better readability

{
	echo '-------------------------------------------------------------'
}

check_script_arguments() # Check whether the argument(s) passed to the script match the expected format

{
	if [ -z "$1" ] # Check whether at least one argument was passed

    	then
        	echo "Usage: $0 <fqdn> or <fqdn1,fqdn2,fqdn3,...>" # And if not, display the correct command syntax
        	exit 1
    	fi

	local fqdn_regex='^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,16}([,]([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,16})*$'
    
    	if ! [[ "$1" =~ $fqdn_regex ]] # Check whether the passed arguments are valid FQDNs
    	then
        	echo 'Invalid domain format. Please provide a valid FQDN or a comma-separated list of FQDNs.'
        	exit 1
    	fi

    	if [[ "$expand" == "--expand" ]]
    	then
		expandmode="1"
    	else
		expandmode="0"
    	fi

}

function dnscheck() # Main function to verify if the conditions (existence and validity of DNS entries) are met

{
	for fqdn in "${FQDNS[@]}" # Loop through the array of FQDNs
    	do 
        	ip_mismatch_found="0"
        	mismatched_ips=""
        	fqdn_ips=$(host $fqdn) 
        	checkips=$(echo "$fqdn_ips" | awk '/has address|IPv6 address/ {print $NF}') # Extract IPv4 and IPv6 addresses

		if [[ -z $checkips ]] # If empty, it's invalid because an IP address is expected
        	then
        		echo -e "$fqdn ${RED}invalid${NC}: no IP address found"
	    		sslok="0"
            		continue
        	fi

        	for addr in $checkips 
        	do
            		# Check if the IP address is in the list of authorized IPs
            		if [[ ! " ${IPS[@]} " =~ " $addr " ]] 
	    		then
                		mismatched_ips+="$addr " # Add to the list
                		ip_mismatch_found="1"
            		fi
        	done

		if [[ $ip_mismatch_found == "1" ]] # Display what is valid and invalid (could be isolated in a separate function)
        	then
            		if [[ -n $mismatched_ips ]]
            		then
                		echo -e "$fqdn ${RED}invalid:${NC} mismatched IPs - $mismatched_ips"
            		else
                		echo -e "$fqdn ${GREEN}valid${NC}"
            		fi
            		sslok="0"
        	else
            		echo -e "$fqdn ${GREEN}valid${NC}"
        	fi
	done
}

function genssl()
{
	if [[ $sslok = 1 ]] && [[ $expandmode = 0 ]]
	then
		certbot -n --agree-tos --email "$email" --installer apache --webroot -w "/home/letsencrypt" --domain "$fqdns"
	
	elif [[ $sslok = 1 ]] && [[ $expandmode = 1 ]]
	then
		certbot -n --agree-tos --email "$email" --installer apache --webroot -w "/home/letsencrypt" --domain "$fqdns" --expand
	
	elif [[ $sslok = 0 ]]
	then
		exit
	
	else
		exit
	fi
}


check_script_arguments $fqdns $expand
print_line
dnscheck $fqdns
print_line
genssl 


