#!/bin/sh
#
# $FreeBSD$
#

# PROVIDE: ix-nginx
# REQUIRE: ix-warden
# BEFORE: nginx django

. /etc/rc.freenas


NGINX_PLUGINS_CONF="${HTTPDDIR}/plugins.conf"
NGINX_FASTCGI_PARAMS="${HTTPDDIR}/fastcgi_params"

get_ssl_certificate_name()
{
	${FREENAS_SQLITE_CMD} ${FREENAS_CONFIG} "
	SELECT
		sc.cert_name
	FROM
		system_settings
	LEFT OUTER JOIN
		system_certificate as sc
	ON
		(stg_guicertificate_id = sc.id)
	ORDER BY
		-system_settings.id
	LIMIT
		1
	"
}

get_ssl_certificate()
{
	local certname

	certname="$(get_ssl_certificate_name)"
	if [ -n "${certname}" ]
	then
		echo "${SSLDIR}/${certname}.crt"
	fi
}

get_ssl_privatekey()
{
	local certname

	certname="$(get_ssl_certificate_name)"
	if [ -n "${certname}" ]
	then
		echo "${SSLDIR}/${certname}.key"
	fi
}

generate_plugins_conf()
{
	local IFS="|"
	local nginx_location

	: > "${NGINX_PLUGINS_CONF}"

        # Workaround: config check fail if it doesnt exist
        mkdir -p /var/tmp/nginx 2> /dev/null > /dev/null

	${FREENAS_SQLITE_CMD} ${FREENAS_CONFIG} "
	SELECT
		id,
		plugin_name,
		plugin_jail,
		plugin_enabled,
		plugin_port,
		plugin_path

	FROM
		plugins_plugins

	ORDER BY
		-id
	" | \
	while read -r id name jail enabled port ppath
	do
		local ipv4=$(jail_get_ipv4 "${jail}")
		local ipv6=$(jail_get_ipv6 "${jail}")
		local jpath=$(jail_get_path "${jail}")
		local ip=

		#
		# Default to IPv4 now if it exists, I'm unsure if
		# this will work with IPv6, needs testing.
		#
		if [ -n "${ipv4}" ]
		then
			jail_get_ip_and_netmask "${ipv4}"
			ip="${JIP}"

		elif [ -n "${ipv6}" ]
		then
			jail_get_ip_and_netmask "${ipv6}"
			ip="${JIP}"
		fi

		if [ -z "${name}" -o -z "${ip}" -o -z "${ppath}" ]
		then
			continue
		fi

		cat<<-__EOF__>>"${NGINX_PLUGINS_CONF}"
		location ~ '/plugins/${name}/${id}/' {
		    fastcgi_pass   ${ip}:${port};
		    include		fastcgi_params;
		    root ${ppath};
__EOF__

		nginx_location="${jpath}/${ppath}/nginx_location"
		if [ -f ${nginx_location} ]; then
			tmp=$(mktemp -t nginx)
			echo "
			events {}
			http {
				server {
					location / {
						$(cat ${nginx_location})
					}
				}
			}
			" > ${tmp}
			${HTTPD} -t -c ${tmp} 2> /dev/null > /dev/null
			if [ $? -eq 0 ]; then
				sed "s/%%PLUGIN_ID%%/${id}/g" ${nginx_location} >> "${NGINX_PLUGINS_CONF}"
			fi

		fi

		cat<<-__EOF__>>"${NGINX_PLUGINS_CONF}"
		}
__EOF__

	done
}


generate_nginx_conf()
{
	local res=1
	local proto="${1}"
	local addr="${2}"
	local addr6="${3}"
	local port="${4}"
	local httpsport="${5}"
	local httpsredirect="${6}"
	local vcenter_https="${7}"
	local working_ssl=false
	local dhparams_file="/data/dhparam.pem"
	local dojo=$(env PYTHONPATH=/usr/local/www/freenasUI/ /usr/local/bin/python -B -S -c 'import settings; print settings.DOJANGO_DOJO_VERSION')

	[ -s /data/dhparam.pem ] || openssl dhparam -rand - 2048 > /data/dhparam.pem
	[ -s /data/dhparam1024.pem ] || openssl dhparam -rand - 1024 > /data/dhparam1024.pem

	if [ "${vcenter_https}" = "1" ]; then
		dhparams_file="/data/dhparam1024.pem"
	fi

	{
	cat << __EOF__
#
#    FreeNAS nginx configuration file
#

user www www;
worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    # reserve 1MB under the name 'proxied' to track uploads
    upload_progress proxied 1m;

    sendfile        on;
    #tcp_nopush     on;
    client_max_body_size 800m;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;
    #upload_store /var/tmp/firmware;
    client_body_temp_path /var/tmp/firmware;
    
    server {
        server_name  localhost;
__EOF__

	if [ "${proto}" = "https" -o "${proto}" = "httphttps" ]; then
                local httpdcert="$(get_ssl_certificate)"
                local httpdkey="$(get_ssl_privatekey)"

		local validcert=0
		${OPENSSL} x509 -in "${httpdcert}" -noout -text -dates -purpose > /dev/null 2>&1
		let "validcert |= $?" > /dev/null
		${OPENSSL} rsa -in "${httpdkey}" -check -noout > /dev/null 2>&1
		let "validcert |= $?" > /dev/null
		# Checking if the key bit lenght is greater than or equal to 1024
		local safecert=$(${OPENSSL} rsa -in "${httpdkey}" -text -noout | grep "Private-Key" | egrep -o '[0-9]' | tr -d "\n")

		if [ ${validcert} -eq 0 -a ${safecert} -ge 1024 ]; then
			working_ssl=true
			# Delete this file (if it exists) now that we have a valid cert (else the alert ui keeps complaining)
			if [ -f /tmp/alert_invalid_ssl_nginx ]; then
			    rm /tmp/alert_invalid_ssl_nginx
			fi

			cat << __EOF__
	listen			${addr}:${httpsport} default_server ssl spdy;
	listen			[${addr6}]:${httpsport} default_server ssl spdy;

	ssl_certificate		"${httpdcert}";
	ssl_certificate_key	"${httpdkey}";
	ssl_dhparam "${dhparams_file}";

	ssl_session_timeout	120m;
	ssl_session_cache	shared:ssl:16m;

        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
	ssl_prefer_server_ciphers on;
	ssl_ciphers EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA256:EDH+aRSA:EECDH:!RC4:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS;
	add_header Strict-Transport-Security max-age=31536000;

	## TODO: OCSP Stapling
	#ssl_stapling on;
	#ssl_stapling_verify on;
	#resolver ${resolver};
	#ssl_trusted_certificate ${ca_chain};
__EOF__
		else
			port=80
			touch /tmp/alert_invalid_ssl_nginx
			# The below to inform the user why his cert was invalidated (if it was invalidated on the basis of key length)
			if [ ${safecert} -lt 1024 ]; then
			    echo "${safecert}" > /tmp/alert_invalid_ssl_nginx
			fi
		fi
	fi

	if [ ! ${working_ssl} -o "${proto}" = "http" -o "${proto}" = "httphttps" ]; then
		echo "        listen       ${addr}:${port};"
		echo "        listen       [${addr6}]:${port};"
	fi

	cat << __EOF__

        location / {
            include fastcgi_params;
            fastcgi_pass 127.0.0.1:9042;
            fastcgi_pass_header Authorization;
            fastcgi_intercept_errors off;
            fastcgi_read_timeout 600m;
            #fastcgi_temp_path /var/tmp/firmware;
            fastcgi_param HTTPS \$https;

            # track uploads in the 'proxied' zone
            # remember connections for 30s after they finished
            track_uploads proxied 30s;
        }

        location /progress {
            # report uploads tracked in the 'proxied' zone
            report_uploads proxied;
        }

        location /dojango {
            alias /usr/local/www/freenasUI/dojango;
        }

        location /static {
            alias /usr/local/www/freenasUI/static;
        }

        location /reporting/graphs {
            alias /var/db/graphs;
        }

        location /dojango/dojo-media/release/${dojo} {
            alias /usr/local/www/dojo;
        }

        location /docs {
        	alias /usr/local/www/data/docs;
        }

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/local/www/nginx-dist;
        }

        #include plugins.conf;
    }
__EOF__

	if [ "${proto}" = "https" -a "${working_ssl}" = true -a "${httpsredirect}" = "1" ]; then
		cat << __EOF__
    server {
	listen ${addr}:80;
	listen [${addr6}]:80;
	server_name localhost;
	return 307 https://\$host:${httpsport}\$request_uri;
    }
__EOF__
	fi

	echo "}";

	} > ${HTTPDCONF}

}


set_stg_guiprotocol()
{
	local res=1
	local proto="${1}"

	if [ "${proto}" = "http" -o "${proto}" = "https" -o "${proto}" = "httphttps" ]
	then
		${FREENAS_SQLITE_CMD} ${FREENAS_CONFIG} "
		UPDATE
			system_settings
		SET
			stg_guiprotocol = '${proto}'
		"
		res=$?
	fi

	return ${res}
}


set_stg_guiport()
{
	local res=1
	local port="${1}"

	: $((port += 0))

	${FREENAS_SQLITE_CMD} ${FREENAS_CONFIG} "
	UPDATE
		system_settings
	SET
		stg_guiport = '${port}'
	"
	res=$?

	return ${res}
}


generate_fastcgi_params()
{
	local IFS="|"

	${FREENAS_SQLITE_CMD} ${FREENAS_CONFIG} "
	SELECT
		stg_guiprotocol

	FROM
		system_settings

	ORDER BY
		-id

	LIMIT 1
	" | \
	while read stg_guiprotocol
	do
		local ssl_enable=0

		stg_guiprotocol=$(echo "${stg_guiprotocol}"|tr a-z A-Z)
		case "${stg_guiprotocol}" in
			HTTP) ssl_enable=0; ;;
			HTTPS) ssl_enable=1; ;;
		esac

		local tmp="$(mktemp /tmp/tmp.XXXXXX)"
		grep -Eiv '^( |\t)*fastcgi_param( |\t)+https( |\t)+' \
			< "${NGINX_FASTCGI_PARAMS}" > "${tmp}"

		if [ "${ssl_enable}" = "1" ]
		then
			echo "fastcgi_param HTTPS on;" >> "${tmp}"
		fi
		mv "${tmp}" "${NGINX_FASTCGI_PARAMS}"
	done
}


get_nginx_settings()
{
	local settings=$(
		local IFS="|"
		${FREENAS_SQLITE_CMD} ${FREENAS_CONFIG} "
		SELECT
			stg_guiprotocol,
			stg_guiaddress,
			stg_guiv6address,
			stg_guiport,
			stg_guihttpsport,
			stg_guihttpsredirect

		FROM
			system_settings

		ORDER BY
			-id

		LIMIT 1
		" | \
		while read -r stg_guiprotocol stg_guiaddress stg_guiv6address stg_guiport stg_guihttpsport stg_guihttpsredirect
		do
			echo "${stg_guiprotocol}|${stg_guiaddress}|${stg_guiv6address}|${stg_guiport}|${stg_guihttpsport}|${stg_guihttpsredirect}"
		done
	)

	local proto=$(echo ${settings}|cut -f1 -d"|" -s|tr A-Z a-z)
	local addr=$(echo ${settings}|cut -f2 -d"|" -s)
	local addr6=$(echo ${settings}|cut -f3 -d"|" -s)
	local port=$(echo ${settings}|cut -f4 -d"|" -s)
	local httpsport=$(echo ${settings}|cut -f5 -d"|" -s)
	local httpsredirect=$(echo ${settings}|cut -f6 -d"|" -s)

	: ${proto:="http"}
	: ${addr:="0.0.0.0"}
	: ${addr6:="::"}

	if [ -z "${httpsport}" ]
	then
		httpsport="443"
	fi
	if [ -z "${port}" ]
	then
		port="80"
	fi

	if [ "${addr}" != "0.0.0.0" -a \
		-z "$(/sbin/ifconfig -a|grep ${addr})" ]; then
		addr="0.0.0.0"
	fi

	if [ "${addr6}" != "::" -a \
		-z "$(/sbin/ifconfig -a|grep ${addr6})" ]; then
		addr6="::"
	fi

	echo "${proto}|${addr}|${addr6}|${port}|${httpsport}|${httpsredirect}"
}


ix_nginx_start()
{
	local settings=$(get_nginx_settings)

	local proto=$(echo "${settings}"|cut -f1 -d"|")
	local addr=$(echo "${settings}"|cut -f2 -d"|")
	local addr6=$(echo "${settings}"|cut -f3 -d"|")
	local port=$(echo "${settings}"|cut -f4 -d"|")
	local httpsport=$(echo "${settings}"|cut -f5 -d"|")
	local httpsredirect=$(echo "${settings}"|cut -f6 -d"|")

	local vcenter_https=$(
		${FREENAS_SQLITE_CMD} ${FREENAS_CONFIG} "
		SELECT
			vc_enable_https

		FROM
			vcp_vcenterauxsettings

		ORDER BY
			-id
		"
	)


	#generate_plugins_conf
	#generate_fastcgi_params

	generate_nginx_conf "${proto}" "${addr}" "${addr6}" "${port}" "${httpsport}" "${httpsredirect}" "${vcenter_https}"

}


name="ix-nginx"
start_cmd='ix_nginx_start'
stop_cmd=':'
            
load_rc_config $name
run_rc_command "$1"
