#!/bin/bash
#==============================================================================
# Description       : Auto-installer for SSL certificates on Apache, Nginx, Haproxy
# Author           : Joachim
# Email            : joachim.coessens@team.blue
#==============================================================================
echo
echo "┌────────────────────────────┐";
echo "│░█▀▄░█▀▀░█▀▀░█▀▄░█░█░█▀█░▀█▀│";
echo "│░█▀▄░█▀▀░█░░░█▀▄░░█░░█▀▀░░█░│";
echo "│░▀░▀░▀▀▀░▀▀▀░▀░▀░░▀░░▀░░░░▀░│";
echo "└────────────────────────────┘";

############FUNCTIONS############

opts() {
  if [[ "$webserver" == "nginx" || "$webserver" == "apache2" ]]; then
    # For nginx and apache (CRT file)
    enddate=$(openssl x509 -in "$find_crt" -noout -enddate | cut -d "=" -f2 2>/dev/null)
    subject=$(openssl x509 -in "$find_crt" -noout -subject | sed 's/subject= //' 2>/dev/null)
  elif [[ "$webserver" == "haproxy" ]]; then
    # For haproxy (PEM file)
    enddate=$(openssl x509 -in "$find_pem" -noout -enddate | cut -d "=" -f2 2>/dev/null)
    subject=$(openssl x509 -in "$find_pem" -noout -subject | sed 's/subject= //' 2>/dev/null)
  else
    echo "Unknown webserver type: $webserver"
    return 1
  fi

  echo "The currently installed certificate is: $subject"
  echo "The enddate of the current certificate is: $enddate"
  echo
}


check_plesk() {
if command -v plesk >/dev/null 2>&1; then
    echo "Plesk is installed, install the certificate via the Plesk interface:"
    echo
    plesk login
    echo
exit 1
fi
}

check_https() {
#    lsof -i tcp:443 | awk '/*:https/ {print $1}' | uniq
ss -tlnp | grep ':443 ' | grep -oP 'users:\(\("\K[^"]+' | sort -u
}

check_pem() {
    pem_file=$(find /tmp -maxdepth 1 -name "${domain}_*.pem" -print -quit)

    if [[ -n "$pem_file" ]]; then
        echo "✅ Pasted and using: $pem_file"
#        split_pem "$pem_file"
    else
        echo "❌ Error: No matching .pem file found in /tmp/. Ensure it follows the format '/tmp/${domain}_$(date +%Y).pem'."
        exit 1
    fi
}

split_pem() {
    sed -n '/-----BEGIN PRIVATE KEY-----/,/-----END PRIVATE KEY-----/p' "$pem_file" > "/tmp/$domain.key"
    sed -n '/-----BEGIN CERTIFICATE-----/,/-----END CERTIFICATE-----/p' "$pem_file" > "/tmp/$domain.crt"

    echo "🔄 PEM file split into key and certificate."
}

function check_nginx_before() {

    if nginx -t 2>&1 | grep -q "test is successful"; then
        echo "✅ Nginx configuration is valid."

    else
        echo "❌ Nginx configuration test failed before doing anything!"
        echo "❗Fix the configuration errors before continuing."
	exit 1
    fi
}

function check_nginx_config() {
    if nginx -t 2>&1 | grep -q "test is successful"; then
        echo "✅ Nginx configuration is valid."
        echo "Reloading Nginx..."
        systemctl reload nginx
        echo "✅ SSL certificates updated successfully!"

    else
        echo "❌ Nginx configuration test failed!"

        read -p "Do you want to roll-back the certificates? (Y/n): " choice
        if [[ "$choice" == "Y" || "$choice" == "y" ]]; then
            echo "Rolling back certificates..."

            cat /tmp/${domain}_backup.key > $find_key
            cat /tmp/${domain}_backup.crt > $find_crt

            echo

                if nginx -t 2>&1 | grep -q "test is successful"; then
                echo "✅ Nginx configuration is valid."
                echo "Reloading Nginx..."
                systemctl reload nginx

                echo "✅ SSL certificates rolled-back successfully!"
                else
                echo "❌ Roll-back failed!"
                echo "❗Fix the configuration errors before reloading."
                fi
        else
         echo "❗Fix the configuration errors before reloading."

        fi
    fi
}

function check_haproxy_config() {
        if haproxy -c -f /etc/haproxy/haproxy.cfg 2>&1 | grep -q "Configuration file is valid"; then
        echo "✅ Haproxy configuration is valid."
        echo "Reloading Haproxy..."
        systemctl reload haproxy
        echo "✅ SSL certificates updated successfully!"
    else
        echo "❌ Haproxy configuration test failed!"
        echo "❗ Fix the configuration errors before reloading."
    fi
}

function check_apache_version() {

    version=$(apache2 -v 2>/dev/null | grep -oP 'Apache/\K[0-9.]+')
    required="2.4.8"

        if [[ "$(printf '%s\n' "$required" "$version" | sort -V | head -n1)" == "$version" && "$version" != "$required" ]]; then
        echo "⚠️ Apache version too old ($version). Check for separate CA file requirement."
    fi

}

function check_apache_before() {
    if apachectl configtest 2>&1 | grep -q "Syntax OK"; then
        echo "✅ Apache configuration is valid."

    else
        echo "❌ Apache configuration test failed before doing anything!"
        echo "❗Fix the configuration errors before continuing."
        exit 1
    fi
}


function check_apache_config() {
    if apachectl configtest 2>&1 | grep -q "Syntax OK"; then
        echo "✅ Apache configuration is valid."
        echo "Reloading Apache..."
        systemctl reload apache2
        echo "✅ SSL certificates updated successfully!"

    else
        echo "❌ Apache configuration test failed!"

        read -p "Do you want to roll-back the certificates? (Y/n): " choice
        if [[ "$choice" == "Y" || "$choice" == "y" ]]; then
            echo "Rolling back certificates..."

            cat /tmp/${domain}_backup.key > $find_key
            cat /tmp/${domain}_backup.crt > $find_crt
            echo

                if nginx -t 2>&1 | grep -q "test is successful"; then
                echo "✅ Apache configuration is valid."
                echo "Reloading Apache ..."
                systemctl reload apache2

                echo "✅ SSL certificates rolled-back successfully!"
                else
                echo "❌ Roll-back failed!"
                echo "Fix the configuration errors before reloading."
                fi
        fi
    fi
}


install_nginx() {
nginx_filters() {
    grep "$domain" | grep -vi "letsencrypt" | grep -vi "dehydrated" | sed 's/.$//' | sort -u
}

if [ ! -d "/etc/nginx/sites-enabled" ] || [ -z "$(ls -A /etc/nginx/sites-enabled)" ]; then

find_files=$(awk '!/^\s*#/ && /ssl_certificate_key/ && /ssl_certificate/ {print FILENAME ":"}' /etc/nginx/conf.d/* | nginx_filters)
find_key=$(awk '!/^\s*#/ && /ssl_certificate_key/ {print ":"; print $2}' /etc/nginx/conf.d/* | nginx_filters)
find_crt=$(awk '!/^\s*#/ && /ssl_certificate / {print ":"; print $2}' /etc/nginx/conf.d/* | nginx_filters)

else

find_files=$(awk '!/^\s*#/ && /ssl_certificate_key/ && /ssl_certificate/ {print FILENAME ":"}' /etc/nginx/sites-enabled/* | nginx_filters)
find_key=$(awk '!/^\s*#/ && /ssl_certificate_key/ {print ":"; print $2}' /etc/nginx/sites-enabled/* | grep "$domain" | nginx_filters)
find_crt=$(awk '!/^\s*#/ && /ssl_certificate / {print ":"; print $2}' /etc/nginx/sites-enabled/* | grep "$domain" | nginx_filters)
fi


    if [[ -n "$find_key" && -n "$find_crt" ]]; then
        printf "I found these SSL bindings: \n"
        printf "⚙️ Config:%s\n"
        printf "$find_files \n"
        echo
        printf "🔑 Key: %s\n" "$find_key"
        printf "📜 Cert: %s\n" "$find_crt"
        echo

        opts

        read -p "Do you wish to continue and update them? (Y/n): " choice
        if [[ "$choice" == "Y" || "$choice" == "y" ]]; then
        read_pem
        check_pem
        split_pem "pem_file"
            echo "Backing up current certificates..."
            mv "$find_key" "/tmp/${domain}_backup.key"
            mv "$find_crt" "/tmp/${domain}_backup.crt"
            echo "💾 /tmp/${domain}_backup.key"
            echo "💾 /tmp/${domain}_backup.crt"
            echo
            echo "Updating certificates..."
            cp "/tmp/$domain.key" "$find_key"
            cp "/tmp/$domain.crt" "$find_crt"
            printf "🔑 Key: %s\n" "$find_key"
            printf "📜 Cert: %s\n" "$find_crt"
	    echo

            check_nginx_config

#            echo "✅ SSL certificates updated successfully!"
        else
            echo "❌ Install canceled."
            exit 1
        fi

    else
        echo "⚠  No SSL bindings found for $domain in Nginx vhosts, please check manually."
        exit 1
    fi
}

install_apache() {

find_files=$(awk '!/^\s*#/ && /SSLCertificateKeyFile/ && /SSLCertificateFile/ {print FILENAME ":"}' /etc/apache2/sites-enabled/*.conf | grep "$domain" | grep -vi "letsencrypt" | grep -vi "dehydrated" |sed 's/.$//' | sort -u)
find_key=$(awk '!/^\s*#/ && /SSLCertificateKeyFile/ {print $2}' /etc/apache2/sites-enabled/* | grep "$domain" | grep -vi "letsencrypt" | grep -vi "dehydrated" | sort -u | sed 's/"//g' | head -n1 | tr -d '\r')
find_crt=$(awk '!/^\s*#/ && /SSLCertificateFile/ {print $2}' /etc/apache2/sites-enabled/* | grep "$domain" | grep -vi "letsencrypt"| grep -vi "dehydrated" | sort -u | sed 's/"//g' | head -n1 | tr -d '\r')

    if [[ -n "$find_key" && -n "$find_crt" ]]; then
        echo "I found these SSL bindings:"
        printf "🔑 Key: %s\n" "$find_key"
        printf "📜 Cert: %s\n" "$find_crt"
	echo
	opts
        echo
        check_apache_version

        read -p "Do you wish to continue and update them? (Y/n): " choice
        if [[ "$choice" == "Y" || "$choice" == "y" ]]; then
        read_pem
        check_pem
        split_pem "pem_file"
            echo "Backing up current certificates..."
            mv "$find_key" "/tmp/${domain}_backup.key"
            mv "$find_crt" "/tmp/${domain}_backup.crt"
            echo "💾 /tmp/${domain}_backup.key"
            echo "💾 /tmp/${domain}_backup.crt"
            echo
            echo "Updating certificates..."
            cp "/tmp/$domain.key" "$find_key"
            cp "/tmp/$domain.crt" "$find_crt"
            printf "🔑 Key: %s\n" "$find_key"
            printf "📜 Cert: %s\n" "$find_crt"
            echo

            check_apache_config

 #           echo "✅ SSL certificates updated successfully!"
        else
            echo "❌ Install canceled."
            exit 1
        fi

    else
echo "⚠  No SSL bindings found for $domain in Apache vhosts, please check manually."
        exit 1
    fi
}


install_haproxy() {

crt_base=""
crt_paths=""

# Parse haproxy.cfg for crt-base and crt paths
while IFS= read -r line; do
    [[ "$line" =~ ^# ]] && continue  # skip comments
    for word in $line; do
        if [[ "$word" == "crt-base" ]]; then
            crt_base=$(echo "$line" | awk '{print $2}')
        elif [[ "$word" == "crt" ]]; then
            path=$(echo "$line" | awk '{for(i=1;i<=NF;i++) if($i=="crt") print $(i+1)}')
            crt_paths+="$path"$'\n'
        fi
    done
done < /etc/haproxy/haproxy.cfg

crt_paths=$(echo "$crt_paths" | sort -u)

find_pem=""

match_cert() {
    local file="$1"
    local base

    base=$(basename "$file")

    # Exact match
    [[ "$base" == "$domain.pem" || "$base" == "$domain.crt" ]] && return 0

    # Wildcards
    [[ "$base" == "wc.$domain.pem" || "$base" == "wc.$domain.crt" ]] && return 0
    [[ "$base" == "_.$domain.pem" || "$base" == "_.$domain.crt" ]] && return 0
    [[ "$base" == "wildcard.$domain.pem" || "$base" == "wildcard.$domain.crt" ]] && return 0

    return 1
}


# Search in configured crt paths
while IFS= read -r path; do
    [[ -z "$path" ]] && continue
    [[ "$path" == *letsencrypt* ]] && continue

    # Apply crt-base if path is relative
    if [[ -n "$crt_base" && "$path" != /* ]]; then
        full_path="$crt_base/$path"
    else
        full_path="$path"
    fi

    if [[ -d "$full_path" ]]; then
        candidate=$(find "$full_path" -type f \( -name "*.crt" -o -name "*.pem" \) | while read -r f; do
            if match_cert "$f"; then
                echo "$f"
                break
            fi
        done)
        [[ -n "$candidate" ]] && find_pem="$candidate" && break
    elif [[ -f "$full_path" ]]; then
        if match_cert "$full_path"; then
            find_pem="$full_path"
            break
        fi
    fi
done <<< "$crt_paths"

# If not found, search whole crt-base directory
if [[ -z "$find_pem" && -n "$crt_base" && -d "$crt_base" ]]; then
    candidate=$(find "$crt_base" -type f \( -name "*.crt" -o -name "*.pem" \) | while read -r f; do
        if match_cert "$f"; then
            echo "$f"
            break
        fi
    done)
    [[ -n "$candidate" ]] && find_pem="$candidate"
fi

# If still not found, fallback to /etc/haproxy/ssl
if [[ -z "$find_pem" && -d /etc/haproxy/ssl ]]; then
    candidate=$(find /etc/haproxy/ssl -type f \( -name "*.crt" -o -name "*.pem" \) | while read -r f; do
        if match_cert "$f"; then
            echo "$f"
            break
        fi
    done)
    [[ -n "$candidate" ]] && find_pem="$candidate"
fi

echo "$find_pem"

    if [[ -n "$find_pem" ]]; then
        echo "I found these SSL certificates:"
        printf "📜 Pem: %s\n" "$find_pem"
	opts
        echo

        read -p "Do you wish to continue and update them? (Y/n): " choice
        if [[ "$choice" == "Y" || "$choice" == "y" ]]; then
            read_pem
            check_pem
	    echo
            echo "Backing up current certificates..."
            mv "$find_pem" "/tmp/${domain}_backup.pem"
            echo "💾 /tmp/${domain}_backup.pem"
	    echo
            echo "Updating certificates..."
            cat $pem_file > $find_pem
	    printf "📜 Pem: %s\n" "$find_pem"
            echo

            check_haproxy_config

        else
            echo "❌ Install canceled."
            exit 1
        fi
    else
        echo "⚠  No SSL bindings found for $domain in Haproxy vhosts, please check manually."
        echo $crt_loc
        exit 1
    fi
}


read_pem(){
echo "Paste your PEM file, then press Ctrl+D on a new line:"
cat > "/tmp/${domain}_$(date +%Y).pem"
}


############MAIN############

manual_mode_install() {
    echo "🔧 Manual mode selected."
    read -p "Domain: " domain
    echo
    read -p "Path to CRT file: " find_crt
    read -p "Path to KEY file: " find_key
    echo

    read -p "Do you wish to continue and update these? (Y/n): " choice
    if [[ "$choice" == "Y" || "$choice" == "y" ]]; then
        read_pem
	check_pem
        split_pem "pem_file"

        echo "Backing up current certificates..."
        mv "$find_key" "/tmp/${domain}_backup.key"
        mv "$find_crt" "/tmp/${domain}_backup.crt"
        echo "💾 /tmp/${domain}_backup.key"
        echo "💾 /tmp/${domain}_backup.crt"
        echo

        echo "Replacing certificates with new ones..."
        cp "/tmp/$domain.key" "$find_key"
        cp "/tmp/$domain.crt" "$find_crt"

        echo "✅ Manual replacement done. Please reload your webserver manually."
    else
        echo "❌ Manual install canceled."
        exit 1
    fi
}

if [[ $1 == "-v" ]]; then
    echo "Version: 1.0"
    exit 0

elif [[ $1 == "-m" ]]; then
    manual_mode_install
    exit 0
fi


echo

check_plesk

## <info> overrule webserver for testing
webserver=$(check_https)
#webserver=apache2

echo "🌐 Detected $(check_https) web server."
echo
read -p "Domain: " domain
echo

case "$webserver" in
    nginx)
        echo "🌐 Using the current Nginx configuration: "
	check_nginx_before
        install_nginx
        echo
        opts
        ;;
    apache2)
        echo "🌐 Using the current Apache configuration: "
        check_apache_before
	install_apache
        echo
        opts
        ;;
    haproxy)
        echo "🌐 Using the current Haproxy configuration:"
        install_haproxy
        echo
        opts
        ;;
    *)
        echo "⚠  No web services found. Please verify manually..."
        exit 1
        ;;
esac
