#!/bin/bash
# shellcheck disable=SC2034,SC2086

#
# Name:         easy-ssl-nginx
# Version:      2.4.9
# Description:  Seedbox SSL Manager (NGINX version)
#
# (c) 2020-2021, Rapidseedbox, alexey@rapidseedbox.com
#

export LANG=en_US
export PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

SC_NAME="$( basename "${0}" )"
SC_VER="$( grep -m 1 -E '^#\s*Version:\s+' "${0}" | awk '{print $NF}' )"

# Obsolete stuff - experiments, etc
OBSOLETE_SUBDOMAINS="box.traefik.me box.rapidseedbox.com"

# Primary client subdomain
SUBDOMAIN="a.seedbox.vip"

# Certificates remote storage URL
SSL_STORAGE_SERVER="rsb-supp.rapidseedbox.com"
SSL_STORAGE_URL="https://${SSL_STORAGE_SERVER}/box-cert/${SUBDOMAIN}"

# Certificate files
CERT_FILES="cert.pem chain.pem fullchain.pem privkey.pem"

# Certificates storage on the box
SSL_DIR="/etc/ssl/${SUBDOMAIN}"

# Log directory
LOG_DIR="/var/log/rsbssl"
[ -d "${LOG_DIR}" ] || mkdir -p "${LOG_DIR}"

# 'nginx' config directory
NGINX_CFG_DIR="/etc/nginx"

#IP="$( ip route get 8.8.8.8 | head -1 | sed -e 's/.*\s*src\s*\([0-9.]*\).*$/\1/' )"
IP="$( ip -o route get to 8.8.8.8 | sed -nre 's/.*\s+src\s+([0-9.]+).*/\1/p' )"
if [ -z "${IP}" ] ; then
    echored "Cannot determine IP address!\n"
    exit 1
fi

SERVER_NAME="$( echo "${IP}" | tr '.' '-' ).${SUBDOMAIN}"

usage () {
        cat <<-EOF

	Request SSL certificate for https://${SERVER_NAME}

	Usage:
	------------
	    ${SC_NAME} [-h] [-b|-n] [-f]

	    -h         - Display this help message
	    -b or -n   - Batch  mode - useful for cronjobs
	    -f         - Force configuration reload 

	EOF
}

# ----------------------------------------------- #
# Color output functions                          #
# ----------------------------------------------- #
__RAINBOWPALETTE="1"
__colortext () {
    if [ "${COLORS}" = "yes" ] ; then
        echo -n "\e[${__RAINBOWPALETTE};${2}m${1}\e[0m"
    else
        echo -n "${1}"
    fi
}
echogreen () {
    echo -ne "$(__colortext "${1}" "32")"
}
echored () {
    echo -ne "$(__colortext "${1}" "31")"
}
echoblue () {
    echo -ne "$(__colortext "${1}" "34")"
}
echopurple () {
    echo -ne "$(__colortext "${1}" "35")"
}
echoyellow () {
    echo -ne "$(__colortext "${1}" "33")"
}
echocyan () {
    echo -ne "$(__colortext "${1}" "36")"
}
echodarkgray () {
    echo -ne "$(__colortext "${1}" "30")"
}
echolightgray () {
    echo -ne "$(__colortext "${1}" "37")"
}


#
# Parse command line
#
COLORS="yes"
OPTIND=1
PARSE_ERR=0
BATCH="no"
FORCE="no"
while getopts ":hbnf" params; do
    case "${params}" in
      h)
          usage ; exit 0
          ;;
      b|n)
          COLORS="no"
          BATCH="yes"
          continue
          ;;
      f)
          FORCE="yes"
          continue
          ;;
      \?) 
          echo "Invalid option: $( echored "-${OPTARG}" )\n"
          PARSE_ERR=1
          ;;
    esac
done

if [ ${PARSE_ERR} -ne 0 ] ; then
    usage ; exit 1
fi
shift "$(( OPTIND - 1 ))"

[ "${BATCH}" = "no" ] && echoyellow "${SC_NAME} ${SC_VER}: Starting\n"

[ "${BATCH}" = "no" ] && echodarkgray "Checking '${SSL_STORAGE_SERVER}' availability"
if ! ping -c 4 "${SSL_STORAGE_SERVER}" > /dev/null 2>&1 ; then
    echored "${SSL_STORAGE_SERVER}: host is not reachable!\n"
    exit 1
fi
[ "${BATCH}" = "no" ] && echodarkgray ":  $( echogreen "OK" )\n"

[ "${BATCH}" = "no" ] && echodarkgray "Checking NGINX status"
if [ ! -d "${NGINX_CFG_DIR}/conf.d" ] ; then
    echored "Service 'nginx' is not installed!\n"
    exit 1
fi
[ "${BATCH}" = "no" ] && echodarkgray ":  $( echogreen "OK" )\n"

# Remove old configuration and certificates
if [ "${FORCE}" = "yes" ] ; then
    echodarkgray "$( rm -rvf "${SSL_DIR}" 2>&1 )\n"
    for _f in \
        "rsb-common-settings-http" \
        "rsb-common-settings-https" \
        "rsb-default.conf" \
        "rsb-proxy-puppeteer.conf" \
        "rsbssl_easy_${SUBDOMAIN}*.conf" \
    ; do
        echodarkgray "$( rm -vf ${NGINX_CFG_DIR}/conf.d/${_f} 2>&1 )\n"
    done
fi

if ! nginx -t > /dev/null 2>&1 ; then
    echodarkgray "NGINX configuration test: $( echored "FAILED" )\n"
    echored "Please run $( echocyan "nginx -t" ) to check and fix the errors first!\n"
    exit 2
fi

#
# Fetch SSL cerificate
#
__wget_err=0
_rc=0
for _f in ${CERT_FILES} ; do
    wget -4 -nc -q --no-check-certificate --timeout=40 --tries=10 -O - \
         "${SSL_STORAGE_URL}/${_f}" > "/tmp/${_f}"
    _rc="$?"
    if [ ${_rc} -ne 0 -o ! -s "/tmp/${_f}" ] ; then
        __wget_err=1
        break
    fi
done

if [ ${__wget_err} -ne 0 ] ; then
    echored "Error fetching ${SSL_STORAGE_URL}/${_f} -> RC: [${_rc}]\n"
    exit 1
fi

#
# Cleaning up some stuff
#
# --- 'FORCE' mode - cleanup current config also
[ "${FORCE}" = "yes" ] && OBSOLETE_SUBDOMAINS="${SUBDOMAIN} ${OBSOLETE_SUBDOMAINS}"
#
for __d in ${OBSOLETE_SUBDOMAINS} ; do
    for __f in \
        "rsbssl_${__d}.conf"        \
        "rsbssl_easy_${__d}.conf"   \
        "rsb-common-settings-http"  \
        "rsb-common-settings-https" \
        "rsb-default.conf"          \
        "rsb-proxy-puppeteer.conf"  \
    ; do
        if [ -e "${MGINX_CFG_DIR}/conf.d/${__f}" ] ; then
            echodarkgray "$( rm -vf "${NGINX_CFG_DIR}/conf.d/${__f}" )\n"
        fi
    done
    if [ -d "/etc/ssl/${__d}" ] ; then
        echodarkgray "$( rm -rvf "/etc/ssl/${__d}" )\n"
    fi
done

[ -d "${SSL_DIR}" ] || echodarkgray "$( mkdir -vp "${SSL_DIR}" )\n"

NGINX_RESTART="no"

for _f in ${CERT_FILES} ; do
    if [ ! -e "${SSL_DIR}/${_f}" ] ; then
        echodarkgray "$( mv -vf "/tmp/${_f}" "${SSL_DIR}/${_f}" )\n"
        NGINX_RESTART="yes"
    elif ! diff -q "/tmp/${_f}" "${SSL_DIR}/${_f}" ; then
        echodarkgray "$( mv -vf "/tmp/${_f}" "${SSL_DIR}/${_f}" )\n"
        NGINX_RESTART="yes"
    else
        rm -f "/tmp/${_f}"
    fi	    
    chmod 600 "${SSL_DIR}/${_f}"
done


#
# Configure NGINX
#
MAIN_CONFIG="no"
if [ ! -e "${NGINX_CFG_DIR}/conf.d/rsbssl_easy_${SUBDOMAIN}.conf" ]
then
    MAIN_CONFIG="yes"
elif ! grep -q -E "\s*server_name\s*${SERVER_NAME}" "${NGINX_CFG_DIR}/conf.d/rsbssl_easy_${SUBDOMAIN}.conf"
then
    MAIN_CONFIG="yes"
fi

PP_CONFIG="no"
if [ "${MAIN_CONFIG}" = "yes" ] ; then
    echodarkgray "Configuring NGINX main site...\n"
    NGINX_RESTART="yes"
    [ -e "${NGINX_CFG_DIR}/dhparam.pem" ] \
        || echodarkgray "$( openssl dhparam -out "${NGINX_CFG_DIR}/dhparam.pem" 2048 )\n"
    cat <<-EOF > "${NGINX_CFG_DIR}/conf.d/rsb-common-settings-http" 
	listen 80;

	location / {
	    return 302 https://\$host\$request_uri;
	}
	EOF
    cat <<-EOF > "${NGINX_CFG_DIR}/conf.d/rsb-common-settings-https" 
	listen 443 ssl http2;
	ssl_stapling on;
	ssl_stapling_verify on;
	ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
	ssl_dhparam /etc/nginx/dhparam.pem;
	ssl_ciphers 'kEECDH+ECDSA+AES128 kEECDH+ECDSA+AES256 kEECDH+AES128 kEECDH+AES256 kEDH+AES128 kEDH+AES256 DES-CBC3-SHA +SHA !aNULL !eNULL !LOW !kECDH !DSS !MD5 !RC4 !EXP !PSK !SRP !CAMELLIA !SEED';
	ssl_prefer_server_ciphers on;
	add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
	ssl_session_cache shared:SSL:10m;
	ssl_session_timeout 10m;

	ssl_certificate "${SSL_DIR}/fullchain.pem";
	ssl_certificate_key "${SSL_DIR}/privkey.pem";
	EOF
    cat <<-EOF > "${NGINX_CFG_DIR}/conf.d/rsbssl_easy_${SUBDOMAIN}.conf"
	server {
	    server_name ${SERVER_NAME};
	    include "${NGINX_CFG_DIR}/conf.d/rsb-common-settings-http";
	}

	server {
	    server_name ${SERVER_NAME};
	    include "${NGINX_CFG_DIR}/conf.d/rsb-common-settings-https";
	    location / {
	        return 404;
	    }
	}
	EOF
    if [ -d "/opt/Proxy-Puppeteer/" -a -e "/usr/local/etc/3proxy/passwd" ] ; then
        PP_CONFIG="yes"
        PROXY_PLAN="unknown"
        if   [ -s "/var/local/ipv4proxy/proxy-plan" ] ; then
            PROXY_PLAN="$( cat "/var/local/ipv4proxy/proxy-plan" )"
        elif [ -s "/var/local/ipv6proxy" ] ; then
            PROXY_PLAN="$( cat "/var/local/ipv6proxy/proxy-plan" )"
        fi

        PP_MAX_CONNS="10"
        case "${PROXY_PLAN}" in
          "a")
              PP_MAX_CONNS="3"
              ;;
          "b")
              PP_MAX_CONNS="5"
              ;;
          "c"|"x")
              PP_MAX_CONNS="10"
              ;;
          "d")
              PP_MAX_CONNS="20"
              ;;
        esac

        cat <<-EOF > "${NGINX_CFG_DIR}/conf.d/rsb-proxy-puppeteer.conf"
	upstream pp {
	    server 127.0.0.1:3000 max_conns=${PP_MAX_CONNS};
	}

	server {
	    server_name pp-${SERVER_NAME};
	    include "${NGINX_CFG_DIR}/conf.d/rsb-common-settings-http";
	}

	server {
	    server_name pp-${SERVER_NAME};
	    include "${NGINX_CFG_DIR}/conf.d/rsb-common-settings-https";

	    location / {
	        auth_basic "Puppeteer";
	        auth_basic_user_file /etc/nginx/htpasswd.puppeteer;
	        #proxy_pass http://pp/render;
	        proxy_read_timeout 180;
	        proxy_pass http://pp/;
	    }
	}
	EOF
        if [ -e "/etc/nginx/htpasswd.puppeteer" ] ; then
            echodarkgray "$( rm -vf "/etc/nginx/htpasswd.puppeteer" )\n"
        fi
        while read line ; do
            flag="-b"
            [ -e "/etc/nginx/htpasswd.puppeteer" ] || flag="${flag} -c"
            username="$( echo "${line}" | awk -F':' '{print $1}' )"
            password="$( echo "${line}" | awk -F':' '{print $3}' )"
            htpasswd ${flag} "/etc/nginx/htpasswd.puppeteer" "${username}" "${password}"
        done < "/usr/local/etc/3proxy/passwd"
    fi


fi



#
# Reload `nginx` service if needed
#
if [ "${NGINX_RESTART}" = "yes" ] ; then
    echodarkgray "Checking NGINX configuration"
    if ! nginx -t > /dev/null 2>&1 ; then
        echodarkgray "NGINX configuration test: $( echored "FAILED" )\n"
        echored "Please run 'nginx -t' to check ad fix...\n"
        exit 2
    fi
    echogreen ":  OK\n"
    if systemctl is-active "nginx" > /dev/null 2>&1 ; then
        echodarkgray "Reloading NGINX service"
        systemctl reload "nginx" > /dev/null 2>&1 \
            && echodarkgray ":  $( echogreen "OK" )\n" \
            || echodarkgray ":  $( echored "FAILED" )\n"
    else
        echored "NGINX service is not active\n"
    fi
fi

#
# Configure `logrotate`
#
if [ -d "/etc/logrotate.d" ] ; then
    cat <<-EOF > "/etc/logrotate.d/ssl-mgr"
	${LOG_DIR}/*.log
	{
	    rotate 8
	    weekly
	    missingok
	    notifempty
	    size 1M
	    compress
	    delaycompress
	}
	EOF
fi

#
# Configure `cron`
#
if [ -d "/etc/cron.d" ] ; then
    cat <<-EOF > "/etc/cron.d/easy-ssl"
	# ${SERVER_NAME}
	MAILTO=""
	PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

	15 */3 * * * root /bin/bash /usr/local/bin/easy-ssl-nginx -b | while IFS= read -r line; do echo "[\$(date -u)]: \${line}"; done | tee -a "${LOG_DIR}/easy-ssl-nginx.log"
	EOF
fi

#
# Voila :)
#
if [    "${NGINX_RESTART}" = "yes"  \
     -o "${BATCH}" = "no"           \
     -o "${FORCE}" = "yes" ]
then
    cat <<-EOF

	Congratulations!
	------------------

	You can now access your server using this URL:
	    $( echocyan "https://${SERVER_NAME}" )

	EOF
    if [ "${PP_CONFIG}" = "yes" ] ; then
        cat <<-EOF
	To access Proxy Puppeteer you can use URL like this:
	    $( echocyan "https://pp-${SERVER_NAME}?url=http://google.com" )

	EOF
    fi
fi

exit 0
