Raphael Schneeberger 7 лет назад
Родитель
Сommit
7eccba6170

+ 277 - 0
bin/v-add-cron-hestia-autoupdate

@@ -0,0 +1,277 @@
+#!/bin/bash
+# info: check letsencrypt domain
+# options: USER DOMAIN [ALIASES] [RESTART] [NOTIFY]
+#
+# The function check and validates domain with Let's Encrypt
+
+
+#----------------------------------------------------------#
+#                    Variable&Function                     #
+#----------------------------------------------------------#
+
+# Argument definition
+user=$1
+domain=$2
+aliases=$3
+restart=$4
+notify=$5
+
+# LE API
+LE_API='https://acme-v02.api.letsencrypt.org'
+
+# Includes
+source $HESTIA/func/main.sh
+source $HESTIA/func/domain.sh
+source $HESTIA/conf/hestia.conf
+
+# encode base64
+encode_base64() {
+    cat |base64 |tr '+/' '-_' |tr -d '\r\n='
+}
+
+# Let's Encrypt v2 curl function
+query_le_v2() {
+
+    protected='{"nonce": "'$3'",'
+    protected=''$protected' "url": "'$1'",'
+    protected=''$protected' "alg": "RS256", "kid": "'$KID'"}'
+    content="Content-Type: application/jose+json"
+
+    payload_=$(echo -n "$2" |encode_base64)
+    protected_=$(echo -n "$protected" |encode_base64)
+    signature_=$(printf "%s" "$protected_.$payload_" |\
+        openssl dgst -sha256 -binary -sign $USER_DATA/ssl/user.key |\
+        encode_base64)
+
+    post_data='{"protected":"'"$protected_"'",'
+    post_data=$post_data'"payload":"'"$payload_"'",'
+    post_data=$post_data'"signature":"'"$signature_"'"}'
+
+    curl -s -i -d "$post_data" "$1" -H "$content"
+}
+
+
+
+#----------------------------------------------------------#
+#                    Verifications                         #
+#----------------------------------------------------------#
+
+check_args '2' "$#" 'USER DOMAIN [ALIASES] [RESTART] [NOTIFY]'
+is_format_valid 'user' 'domain'
+is_system_enabled "$MAIL_SYSTEM" 'MAIL_SYSTEM'
+is_object_valid 'user' 'USER' "$user"
+is_object_unsuspended 'user' 'USER' "$user"
+is_object_valid 'mail' 'DOMAIN' "$domain"
+is_object_unsuspended 'mail' 'DOMAIN' "$domain"
+is_object_value_empty 'mail' 'DOMAIN' "$domain" '$SSL'
+
+
+#----------------------------------------------------------#
+#                       Action                             #
+#----------------------------------------------------------#
+# Parsing domain data
+get_domain_values 'web'
+
+# Registering LetsEncrypt user account
+$BIN/v-add-letsencrypt-user $user
+if [ "$?" -ne 0  ]; then
+    touch $HESTIA/data/queue/letsencrypt.pipe
+    sed -i "/ $domain /d" $HESTIA/data/queue/letsencrypt.pipe
+    send_notice "LETSENCRYPT" "Account registration failed"
+    check_result $E_CONNECT "LE account registration" > /dev/null
+fi
+
+# Parsing LetsEncrypt account data
+source $USER_DATA/ssl/le.conf
+
+# Checking wildcard alias
+if [ "$aliases" = "*.$domain" ]; then
+    wildcard='yes'
+    proto="dns-01"
+    if [ ! -e "$HESTIA/data/users/$user/dns/$domain.conf" ]; then
+        check_result $E_NOTEXIST "DNS domain $domain doesn't exist"
+    fi
+else
+    proto="http-01"
+fi
+
+# Requesting nonce / STEP 1
+answer=$(curl -s -I "$LE_API/directory")
+nonce=$(echo "$answer" |grep Nonce |cut -f2 -d \ |tr -d '\r\n')
+status=$(echo "$answer"|grep HTTP/1.1 |tail -n1 |cut -f 2 -d ' ')
+if [[ "$status" -ne 200 ]]; then
+    check_result $E_CONNECT "Let's Encrypt nonce request status $status"
+fi
+
+# Placing new order / STEP 2
+url="$LE_API/acme/new-order"
+payload='{"identifiers":['
+for identifier in $(echo $domain,$aliases |tr ',' '\n' |sort -u); do
+    payload=$payload'{"type":"dns","value":"'$identifier'"},'
+done
+payload=$(echo "$payload"|sed "s/,$//")
+payload=$payload']}'
+answer=$(query_le_v2 "$url" "$payload" "$nonce")
+nonce=$(echo "$answer" |grep Nonce |cut -f2 -d \ |tr -d '\r\n')
+authz=$(echo "$answer" |grep "acme/authz" |cut -f2 -d '"')
+finalize=$(echo "$answer" |grep 'finalize":' |cut -f4 -d '"')
+status=$(echo "$answer" |grep HTTP/1.1 |tail -n1 |cut -f2 -d ' ')
+if [[ "$status" -ne 201 ]]; then
+    check_result $E_CONNECT "Let's Encrypt new auth status $status"
+fi
+
+# Requesting authorization token / STEP 3
+for auth in $authz; do
+    payload=''
+    answer=$(query_le_v2 "$auth" "$payload" "$nonce")
+    url=$(echo "$answer" |grep -A3 $proto |grep url |cut -f 4 -d \")
+    token=$(echo "$answer" |grep -A3 $proto |grep token |cut -f 4 -d \")
+    nonce=$(echo "$answer" |grep Nonce |cut -f2 -d \ |tr -d '\r\n')
+    status=$(echo "$answer"|grep HTTP/1.1 |tail -n1 |cut -f 2 -d ' ')
+    if [[ "$status" -ne 200 ]]; then
+        check_result $E_CONNECT "Let's Encrypt acme/authz bad status $status"
+    fi
+
+    # Accepting challenge / STEP 4
+    if [ "$wildcard" = 'yes'  ]; then
+        record=$(printf "%s" "$token.$THUMB" |\
+            openssl dgst -sha256 -binary |encode_base64)
+        old_records=$($BIN/v-list-dns-records $user $domain plain|grep 'TXT')
+        old_records=$(echo "$old_records" |grep _acme-challenge |cut -f 1)
+        for old_record in $old_records; do
+            $BIN/v-delete-dns-record $user $domain $old_record
+        done
+        $BIN/v-add-dns-record $user $domain "_acme-challenge" "TXT" $record
+        check_result $? "DNS _acme-challenge record wasn't created"
+    else
+        if [ "$WEB_SYSTEM" = 'nginx' ] || [ ! -z "$PROXY_SYSTEM" ]; then
+            conf="$HOMEDIR/$user/conf/web/$domain/nginx.conf_letsencrypt"
+            sconf="$HOMEDIR/$user/conf/web/$domain/nginx.ssl.conf_letsencrypt"
+            if [ ! -e "$conf" ]; then
+                echo 'location ~ "^/\.well-known/acme-challenge/(.*)$" {' \
+                    > $conf
+                echo '    default_type text/plain;' >> $conf
+                echo '    return 200 "$1.'$THUMB'";' >> $conf
+                echo '}' >> $conf
+            fi
+            if [ ! -e "$sconf" ]; then
+                ln -s "$conf" "$sconf"
+            fi
+            $BIN/v-restart-proxy
+            check_result $? "Proxy restart failed" > /dev/null
+
+        else
+            well_known="$HOMEDIR/$user/web/$rdomain/public_html/.well-known"
+            acme_challenge="$well_known/acme-challenge"
+            mkdir -p $acme_challenge
+            echo "$token.$THUMB" > $acme_challenge/$token
+            chown -R $user:$user $well_known
+        fi
+        $BIN/v-restart-web
+        check_result $? "Web restart failed" > /dev/null
+    fi
+
+    # Requesting ACME validation / STEP 5
+    validation_check=$(echo "$answer" |grep '"valid"')
+    if [[ ! -z "$validation_check" ]]; then
+        validation='valid'
+    else
+        validation='pending'
+    fi
+
+    # Doing pol check on status
+    i=1
+    while [ "$validation" = 'pending' ]; do
+        payload='{}'
+        answer=$(query_le_v2 "$url" "$payload" "$nonce")
+        validation=$(echo "$answer"|grep -A1 $proto |tail -n1|cut -f4 -d \")
+        nonce=$(echo "$answer" |grep Nonce |cut -f2 -d \ |tr -d '\r\n')
+        status=$(echo "$answer"|grep HTTP/1.1 |tail -n1 |cut -f 2 -d ' ')
+        if [[ "$status" -ne 200 ]]; then
+            check_result $E_CONNECT "Let's Encrypt validation status $status"
+        fi
+
+        i=$((i + 1))
+        if [ "$i" -gt 10 ]; then
+            check_result $E_CONNECT "Let's Encrypt domain validation timeout"
+        fi
+        sleep 1
+    done
+    if [ "$validation" = 'invalid' ]; then
+        check_result $E_CONNECT "Let's Encrypt domain verification failed"
+    fi
+done
+
+# Generating new ssl certificate
+ssl_dir=$($BIN/v-generate-ssl-cert "$domain" "info@$domain" "US" "California"\
+    "San Francisco" "Hestia" "IT" "$aliases" |tail -n1 |awk '{print $2}')
+
+# Sending CSR to finalize order / STEP 6
+csr=$(openssl req -in $ssl_dir/$domain.csr -outform DER |encode_base64)
+payload='{"csr":"'$csr'"}'
+answer=$(query_le_v2 "$finalize" "$payload" "$nonce")
+nonce=$(echo "$answer" |grep Nonce |cut -f2 -d \ |tr -d '\r\n')
+status=$(echo "$answer"|grep HTTP/1.1 |tail -n1 |cut -f 2 -d ' ')
+certificate=$(echo "$answer"|grep 'certificate":' |cut -f4 -d '"')
+if [[ "$status" -ne 200 ]]; then
+    check_result $E_CONNECT "Let's Encrypt finalize bad status $status"
+fi
+
+# Downloading signed certificate / STEP 7
+curl -s "$certificate" -o $ssl_dir/$domain.pem
+
+# Splitting up downloaded pem
+crt_end=$(grep -n END $ssl_dir/$domain.pem |head -n1 |cut -f1 -d:)
+head -n $crt_end $ssl_dir/$domain.pem > $ssl_dir/$domain.crt
+
+pem_lines=$(wc -l $ssl_dir/$domain.pem |cut -f 1 -d ' ')
+ca_end=$(grep -n  "BEGIN" $ssl_dir/$domain.pem |tail -n1 |cut -f 1 -d :)
+ca_end=$(( pem_lines - crt_end + 1 ))
+tail -n $ca_end $ssl_dir/$domain.pem > $ssl_dir/$domain.ca
+
+# Temporary fix for double "END CERTIFICATE"
+if [[ $(head -n 1 $ssl_dir/$domain.ca) = "-----END CERTIFICATE-----" ]]; then
+    sed -i '1,2d' $ssl_dir/$domain.ca
+fi
+
+# Adding SSL
+$BIN/v-delete-mail-domain-ssl $user $domain >/dev/null 2>&1
+$BIN/v-add-mail-domain-ssl $user $domain $ssl_dir
+
+if [ "$?" -ne '0' ]; then
+    touch $HESTIA/data/queue/letsencrypt.pipe
+    sed -i "/ $domain /d" $HESTIA/data/queue/letsencrypt.pipe
+    send_notice 'LETSENCRYPT' "$domain certificate installation failed"
+    check_result $? "SSL install" > /dev/null
+fi
+
+# Adding LE autorenew cronjob
+if [ -z "$(grep v-update-lets $HESTIA/data/users/admin/cron.conf)" ]; then
+    min=$(generate_password '012345' '2')
+    hour=$(generate_password '1234567' '1')
+    cmd="sudo $BIN/v-update-letsencrypt-ssl"
+    $BIN/v-add-cron-job admin "$min" "$hour" '*' '*' '*' "$cmd" > /dev/null
+fi
+
+# Updating letsencrypt key
+if [ -z "$LETSENCRYPT" ]; then
+    add_object_key "mail" 'DOMAIN' "$domain" 'LETSENCRYPT' 'SUSPENDED'
+fi
+
+update_object_value 'mail' 'DOMAIN' "$domain" 'LETSENCRYPT' 'yes'
+
+#----------------------------------------------------------#
+#                        Hestia                            #
+#----------------------------------------------------------#
+
+# Deleting task from queue
+touch $HESTIA/data/queue/letsencrypt.pipe
+sed -i "/ $domain /d" $HESTIA/data/queue/letsencrypt.pipe
+
+# Notifying user
+send_notice 'LETSENCRYPT' "$domain SSL has been installed successfully"
+
+# Logging
+log_event "$OK" "$ARGUMENTS"
+
+exit

+ 6 - 7
bin/v-add-mail-domain

@@ -21,6 +21,7 @@ dkim_size=${6-1024}
 source $HESTIA/func/main.sh
 source $HESTIA/func/domain.sh
 source $HESTIA/conf/hestia.conf
+source $HESTIA/func/ip.sh
 
 # Define mail user
 if [ "$MAIL_SYSTEM" = 'exim4' ]; then
@@ -32,7 +33,7 @@ fi
 # Additional argument formatting
 format_domain
 format_domain_idn
-
+get_user_ip
 
 #----------------------------------------------------------#
 #                    Verifications                         #
@@ -53,13 +54,11 @@ is_dir_symlink $HOMEDIR/$user/mail
 #----------------------------------------------------------#
 
 # Generating timestamp
-time_n_date=$(date +'%T %F')
-time=$(echo "$time_n_date" |cut -f 1 -d \ )
-date=$(echo "$time_n_date" |cut -f 2 -d \ )
+new_timestamp
 
 # Adding domain to mail.conf
 s="DOMAIN='$domain' ANTIVIRUS='$antivirus' ANTISPAM='$antispam' DKIM='$dkim'"
-s="$s CATCHALL='' ACCOUNTS='0' U_DISK='0' SUSPENDED='no' TIME='$time'"
+s="$s SSL='no' LETSENCRYPT='no' CATCHALL='' ACCOUNTS='0' WEBMAIL='yes' U_DISK='0' SUSPENDED='no' TIME='$time'"
 s="$s DATE='$date'"
 echo $s >> $USER_DATA/mail.conf
 touch $USER_DATA/mail/$domain.conf
@@ -128,15 +127,15 @@ if [ ! -z "$DNS_SYSTEM" ] && [ "$dkim" = 'yes' ]; then
     fi
 fi
 
-
 #----------------------------------------------------------#
 #                       Hestia                             #
 #----------------------------------------------------------#
 
 # Increasing domain value
 increase_user_value "$user" '$U_MAIL_DOMAINS'
+
 if [ "$dkim" = 'yes' ]; then
-    increase_user_value "$user" '$U_MAIL_DKMI'
+    increase_user_value "$user" '$U_MAIL_DKIM'
 fi
 
 # Logging

+ 97 - 0
bin/v-add-mail-domain-ssl

@@ -0,0 +1,97 @@
+#!/bin/bash
+# info: add mail SSL for $domain
+# options: USER DOMAIN SSL_DIR [RESTART]
+#
+# The function turns on SSL support for a mail domain. Parameter ssl_dir
+# is a path to a directory where 2 or 3 ssl files can be found. Certificate file 
+# mail.domain.tld.crt and its key mail.domain.tld.key are mandatory. Certificate
+# authority mail.domain.tld.ca file is optional.
+
+#----------------------------------------------------------#
+#                    Variable&Function                     #
+#----------------------------------------------------------#
+
+# Argument definition
+user=$1
+domain=$2
+ssl_dir=$3
+restart="$3"
+
+# Additional argument formatting
+if [[ "$domain" =~ [[:upper:]] ]]; then
+    domain=$(echo "$domain" |tr '[:upper:]' '[:lower:]')
+fi
+if [[ "$domain" =~ ^www\..* ]]; then
+    domain=$(echo "$domain" |sed -e "s/^www.//")
+fi
+if [[ "$domain" =~ .*\.$ ]]; then
+    domain=$(echo "$domain" |sed -e "s/\.$//")
+fi
+
+domain=$(idn -t --quiet -u "$domain" )
+domain_idn=$(idn -t --quiet -a "$domain")
+
+# Includes
+source $HESTIA/func/main.sh
+source $HESTIA/func/domain.sh
+source $HESTIA/func/ip.sh
+source $HESTIA/conf/hestia.conf
+
+# Additional argument formatting
+format_domain
+format_domain_idn
+get_user_ip
+
+#----------------------------------------------------------#
+#                    Verifications                         #
+#----------------------------------------------------------#
+
+check_args '3' "$#" 'USER DOMAIN SSL_DIR [RESTART]'
+is_format_valid 'user' 'domain' 'ssl_dir'
+is_system_enabled "$MAIL_SYSTEM" 'MAIL_SYSTEM'
+is_object_valid 'user' 'USER' "$user"
+is_object_unsuspended 'user' 'USER' "$user"
+is_object_valid 'mail' 'DOMAIN' "$domain"
+is_object_unsuspended 'mail' 'DOMAIN' "$domain"
+is_object_value_empty 'mail' 'DOMAIN' "$domain" '$SSL'
+is_object_valid 'web' 'DOMAIN' "$domain"
+is_object_unsuspended 'web' 'DOMAIN' "$domain"
+is_web_domain_cert_valid
+
+#----------------------------------------------------------#
+#                       Action                             #
+#----------------------------------------------------------#
+
+# Call routine to add SSL configuration to mail domain
+add_mail_ssl_config
+
+# Increase value for domain
+increase_user_value "$user" '$U_MAIL_SSL'
+
+# Set SSL as enabled in configuration
+update_object_value 'mail' 'DOMAIN' "$domain" '$SSL' "yes"
+
+# Refresh webmail configuration
+if [ ! -z "$WEB_SYSTEM" ]; then
+    add_ssl_webmail_config
+
+    # Restart web services for webmail changes to take effect
+    $BIN/v-restart-web $restart
+    $BIN/v-restart-proxy $restart
+fi
+
+#----------------------------------------------------------#
+#                       Hestia                             #
+#----------------------------------------------------------#
+
+# Restarting mail server
+$BIN/v-restart-mail $restart
+$BIN/v-restart-service $IMAP_SYSTEM $restart
+
+check_result $? "Mail restart failed" >/dev/null
+
+# Logging
+log_history "enabled mail ssl support for $domain"
+log_event "$OK" "$ARGUMENTS"
+
+exit

+ 1 - 0
bin/v-add-user

@@ -179,6 +179,7 @@ U_DNS_RECORDS='0'
 U_MAIL_DOMAINS='0'
 U_MAIL_DKIM='0'
 U_MAIL_ACCOUNTS='0'
+U_MAIL_SSL='0'
 U_DATABASES='0'
 U_CRON_JOBS='0'
 U_BACKUPS='0'

+ 68 - 0
bin/v-add-web-domain-ssl-force

@@ -0,0 +1,68 @@
+#!/bin/bash
+# info: change domain ssl certificate
+# options: USER DOMAIN SSL_DIR [RESTART]
+#
+# The function changes SSL domain certificate and the key. If ca file present
+# it will be replaced as well.
+
+
+#----------------------------------------------------------#
+#                    Variable&Function                     #
+#----------------------------------------------------------#
+
+# Argument definition
+user=$1
+domain=$2
+domain_idn=$2
+restart=$3
+
+# Includes
+source $HESTIA/func/main.sh
+source $HESTIA/func/domain.sh
+source $HESTIA/conf/hestia.conf
+
+# Additional argument formatting
+format_domain
+format_domain_idn
+
+
+#----------------------------------------------------------#
+#                    Verifications                         #
+#----------------------------------------------------------#
+
+check_args '3' "$#" 'USER DOMAIN SSL_DIR [RESTART]'
+is_format_valid 'user' 'domain' 'ssl_dir'
+is_system_enabled "$MAIL_SYSTEM" 'MAIL_SYSTEM'
+is_object_valid 'user' 'USER' "$user"
+is_object_unsuspended 'user' 'USER' "$user"
+is_object_valid 'mail' 'DOMAIN' "$domain_idn"
+is_object_unsuspended 'mail' 'DOMAIN' "$domain_idn"
+is_object_value_empty 'mail' 'DOMAIN' "$domain_idn" '$SSL'
+is_web_domain_cert_valid
+
+
+#----------------------------------------------------------#
+#                       Action                             #
+#----------------------------------------------------------#
+
+# Remove old configuration
+del_mail_ssl_config
+
+# Create new configuration
+add_mail_ssl_config
+
+#----------------------------------------------------------#
+#                       Hestia                             #
+#----------------------------------------------------------#
+
+# Restarting mail server
+$BIN/v-restart-mail $restart
+service dovecot restart
+service exim4 restart
+check_result $? "Mail restart failed" >/dev/null
+
+# Logging
+log_history "changed ssl certificate for $domain"
+log_event "$OK" "$ARGUMENTS"
+
+exit

+ 61 - 0
bin/v-change-sys-pma

@@ -0,0 +1,61 @@
+#!/bin/bash
+# info: deleting letsencrypt ssl cetificate for domain
+# options: USER DOMAIN [RESTART]
+#
+# The function turns off letsencrypt SSL support for a
+# mail domain.
+
+
+#----------------------------------------------------------#
+#                    Variable&Function                     #
+#----------------------------------------------------------#
+
+# Argument definition
+user=$1
+domain=$2
+restart=$3
+
+# Includes
+source $HESTIA/func/main.sh
+source $HESTIA/func/domain.sh
+source $HESTIA/conf/hestia.conf
+
+
+#----------------------------------------------------------#
+#                    Verifications                         #
+#----------------------------------------------------------#
+
+check_args '2' "$#" 'USER DOMAIN [RESTART]'
+is_format_valid 'user' 'domain'
+is_system_enabled "$WEB_SYSTEM" 'WEB_SYSTEM'
+is_system_enabled "$WEB_SSL" 'SSL_SUPPORT'
+is_object_valid 'user' 'USER' "$user"
+is_object_unsuspended 'user' 'USER' "$user"
+is_object_valid 'mail' 'DOMAIN' "$domain"
+is_object_unsuspended 'mail' 'DOMAIN' "$domain"
+is_object_value_exist 'mail' 'DOMAIN' "$domain" '$LETSENCRYPT'
+
+#----------------------------------------------------------#
+#                       Action                             #
+#----------------------------------------------------------#
+
+# Delete SSL
+$BIN/v-delete-mail-domain-ssl $user $domain $restart >/dev/null 2>&1
+check_result $? "SSL delete" >/dev/null
+
+
+#----------------------------------------------------------#
+#                       Hestia                             #
+#----------------------------------------------------------#
+
+# Updating letsencrypt flag
+update_object_value 'web' 'DOMAIN' "$domain" '$LETSENCRYPT' 'no'
+
+# Restarting web
+$BIN/v-restart-mail $restart
+check_result $? "Mail restart failed" >/dev/null
+
+# Logging
+log_event "$OK" "$ARGUMENTS"
+
+exit

+ 9 - 1
bin/v-delete-mail-domain

@@ -62,6 +62,10 @@ if [ "$DKIM" = 'yes' ] && [ -e "$USER_DATA/dns/$domain.conf" ]; then
     done
 fi
 
+# Delete SSL certificates and configuration
+if [ "$SSL" = 'yes' ]; then
+    del_mail_ssl_config
+fi
 
 #----------------------------------------------------------#
 #                       Hestia                             #
@@ -77,10 +81,14 @@ rm -f $USER_DATA/mail/*@$domain.msg
 # Decreasing domain value
 decrease_user_value "$user" '$U_MAIL_DOMAINS'
 if [ "$DKIM" = 'yes' ]; then
-    decrease_user_value "$user" '$U_MAIL_DKMI'
+    decrease_user_value "$user" '$U_MAIL_DKIM'
 fi
 decrease_user_value "$user" '$U_MAIL_ACCOUNTS' "$accounts"
 
+# Restart servers
+$BIN/v-restart-web $restart
+$BIN/v-restart-proxy $restart
+
 # Logging
 log_history "deleted mail domain $domain"
 log_event "$OK" "$ARGUMENTS"

+ 68 - 0
bin/v-delete-mail-domain-ssl

@@ -0,0 +1,68 @@
+#!/bin/bash
+# info: delete mail domain ssl support
+# options: USER DOMAIN
+#
+# The function delete ssl certificates.
+
+#----------------------------------------------------------#
+#                    Variable&Function                     #
+#----------------------------------------------------------#
+
+# Includes
+source $HESTIA/func/main.sh
+source $HESTIA/func/domain.sh
+source $HESTIA/conf/hestia.conf
+
+# Argument definition
+user=$1
+domain=$2
+
+# Additional argument formatting
+format_domain
+format_domain_idn
+
+#----------------------------------------------------------#
+#                    Verifications                         #
+#----------------------------------------------------------#
+
+check_args '2' "$#" 'USER DOMAIN'
+is_format_valid 'user' 'domain'
+is_system_enabled "$MAIL_SYSTEM" 'MAIL_SYSTEM'
+is_object_valid 'user' 'USER' "$user"
+is_object_unsuspended 'user' 'USER' "$user"
+is_object_valid 'mail' 'DOMAIN' "$domain"
+is_object_unsuspended 'mail' 'DOMAIN' "$domain"
+is_object_value_exist 'mail' 'DOMAIN' "$domain" '$SSL'
+
+
+#----------------------------------------------------------#
+#                       Action                             #
+#----------------------------------------------------------#
+
+# Delete mail domain SSL configuration
+del_mail_ssl_config
+
+# Delete SSL webmail configuration
+if [ ! -z "$WEB_SYSTEM" ]; then
+    del_webmail_ssl_config
+fi
+
+#----------------------------------------------------------#
+#                       Hestia                              #
+#----------------------------------------------------------#
+
+# Updating config
+update_object_value 'mail' 'DOMAIN' "$domain" '$SSL' 'no'
+decrease_user_value "$user" '$U_MAIL_SSL'
+
+# Restarting mail server
+$BIN/v-restart-mail $restart
+service dovecot restart
+service exim4 restart
+check_result $? "Mail restart failed" >/dev/null
+
+# Logging
+log_history "disabled mail SSL support on $domain"
+log_event "$OK" "$ARGUMENTS"
+
+exit

+ 7 - 3
bin/v-delete-web-domain-ssl-force

@@ -28,6 +28,8 @@ json_list() {
         "CATCHALL": "'$CATCHALL'",
         "ACCOUNTS": "'$ACCOUNTS'",
         "U_DISK": "'$U_DISK'",
+        "SSL": "'$SSL'",
+        "LETSENCRYPT": "'$LETSENCRYPT'",
         "SUSPENDED": "'$SUSPENDED'",
         "TIME": "'$TIME'",
         "DATE": "'$DATE'"
@@ -44,6 +46,8 @@ shell_list() {
     echo "CATCHALL:       $CATCHALL"
     echo "ACCOUNTS:       $ACCOUNTS"
     echo "DISK:           $U_DISK"
+    echo "SSL:            $SSL"
+    echo "LETSENCRYPT:    $LETSENCRYPT"
     echo "SUSPENDED:      $SUSPENDED"
     echo "TIME:           $TIME"
     echo "DATE:           $DATE"
@@ -52,15 +56,15 @@ shell_list() {
 # PLAIN list function
 plain_list() {
     echo -ne "$DOMAIN\t$ANTIVIRUS\t$ANTISPAM\t$DKIM\t$CATCHALL\t"
-    echo -e "$ACCOUNTS\t$U_DISK\t$SUSPENDED\t$TIME\t$DATE"
+    echo -e "$ACCOUNTS\t$U_DISK\t$SSL\t$LETSENCRYPT\t$SUSPENDED\t$TIME\t$DATE"
 }
 
 # CSV list function
 csv_list() {
     echo -n "DOMAIN,ANTIVIRUS,ANTISPAM,DKIM,CATCHALL,ACCOUNTS,U_DISK,"
-    echo "SUSPENDED,TIME,DATE"
+    echo "SSL,LETSENCRYPT,SUSPENDED,TIME,DATE"
     echo -n "$DOMAIN,$ANTIVIRUS,$ANTISPAM,$DKIM,$CATCHALL,$ACCOUNTS,$U_DISK"
-    echo "$SUSPENDED,$TIME,$DATE"
+    echo "$SSL,$LETSENCRYPT,$SUSPENDED,$TIME,$DATE"
 }
 
 

+ 150 - 0
bin/v-list-mail-domain-ssl

@@ -0,0 +1,150 @@
+#!/bin/bash
+# info: list mail domain ssl certificate
+# options: USER DOMAIN [FORMAT]
+#
+# The function of obtaining domain ssl files.
+
+
+#----------------------------------------------------------#
+#                    Variable&Function                     #
+#----------------------------------------------------------#
+
+# Argument definition
+user=$1
+domain=$2
+format=${3-shell}
+
+# Includes
+source $HESTIA/func/main.sh
+
+# Additional argument formatting
+format_domain
+format_domain_idn
+
+# JSON list function
+json_list() {
+    echo '{'
+    echo -e "\t\"$domain_idn\": {"
+    echo "        \"CRT\": \"$crt\","
+    echo "        \"KEY\": \"$key\","
+    echo "        \"CA\": \"$ca\","
+    echo "        \"SUBJECT\": \"$subj\","
+    echo "        \"ALIASES\": \"$alt_dns\","
+    echo "        \"NOT_BEFORE\": \"$before\","
+    echo "        \"NOT_AFTER\": \"$after\","
+    echo "        \"SIGNATURE\": \"$signature\","
+    echo "        \"PUB_KEY\": \"$pub_key\","
+    echo "        \"ISSUER\": \"$issuer\""
+    echo -e "\t}\n}"
+}
+
+# SHELL list function
+shell_list() {
+    if [ ! -z "$crt" ]; then
+        echo -e "$crt"
+    fi
+    if [ ! -z "$key" ]; then
+        echo -e "\n$key"
+    fi
+    if [ ! -z "$ca" ]; then
+        echo -e "\n$ca"
+    fi
+    if [ ! -z "$crt" ]; then
+        echo
+        echo
+        echo "SUBJECT:        $subj"
+        if [ ! -z "$alt_dns" ]; then
+            echo "ALIASES:        ${alt_dns//,/ }"
+        fi
+        echo "VALID FROM:     $before"
+        echo "VALID TIL:      $after"
+        echo "SIGNATURE:      $signature"
+        echo "PUB_KEY:        $pub_key"
+        echo "ISSUER:         $issuer"
+    fi
+}
+
+# PLAIN list function
+plain_list() {
+    if [ ! -z "$crt" ]; then
+        echo -e "$crt"
+    fi
+    if [ ! -z "$key" ]; then
+        echo -e "\n$key"
+    fi
+    if [ ! -z "$ca" ]; then
+        echo -e "\n$ca"
+    fi
+    if [ ! -z "$crt" ]; then
+        echo "$subj"
+        echo "${alt_dns//,/ }"
+        echo "$before"
+        echo "$after"
+        echo "$signature"
+        echo "$pub_key"
+        echo "$issuer"
+    fi
+
+}
+
+# CSV list function
+csv_list() {
+    echo -n "CRT,KEY,CA,SUBJECT,ALIASES,NOT_BEFORE,NOT_AFTER,SIGNATURE,"
+    echo "PUB_KEY,ISSUER"
+    echo -n "\"$crt\",\"$key\",\"$ca\",\"$subj\",\"${alt_dns//,/ }\","
+    echo "\"$before\",\"$after\",\"$signature\",\"$pub_key\",\"$issuer\""
+}
+
+
+#----------------------------------------------------------#
+#                    Verifications                         #
+#----------------------------------------------------------#
+
+check_args '2' "$#" 'USER DOMAIN [FORMAT]'
+is_object_valid 'user' 'USER' "$user"
+is_object_valid 'mail' 'DOMAIN' "$domain_idn"
+
+
+#----------------------------------------------------------#
+#                       Action                             #
+#----------------------------------------------------------#
+
+# Parsing domain SSL certificate
+if [ -e "$USER_DATA/ssl/mail.$domain.crt" ]; then
+    crt=$(cat $USER_DATA/ssl/mail.$domain.crt |sed ':a;N;$!ba;s/\n/\\n/g')
+
+    info=$(openssl x509 -text -in $USER_DATA/ssl/mail.$domain.crt)
+    subj=$(echo "$info" |grep Subject: |cut -f 2 -d =)
+    before=$(echo "$info" |grep Before: |sed -e "s/.*Before: //")
+    after=$(echo "$info" |grep "After :" |sed -e "s/.*After : //")
+    signature=$(echo "$info" |grep "Algorithm:" |head -n1 )
+    signature=$(echo "$signature"| sed -e "s/.*Algorithm: //")
+    pub_key=$(echo "$info" |grep Public-Key: |cut -f2 -d \( | tr -d \))
+    issuer=$(echo "$info" |grep Issuer: |sed -e "s/.*Issuer: //")
+    alt_dns=$(echo "$info" |grep DNS |sed -e 's/DNS:/\n/g' |tr -d ',')
+    alt_dns=$(echo "$alt_dns" |tr -d ' ' |sed -e "/^$/d")
+    alt_dns=$(echo "$alt_dns" |sed -e ':a;N;$!ba;s/\n/,/g')
+fi
+
+if [ -e "$USER_DATA/ssl/mail.$domain.key" ]; then
+    key=$(cat $USER_DATA/ssl/mail.$domain.key |sed ':a;N;$!ba;s/\n/\\n/g')
+fi
+
+if [ -e "$USER_DATA/ssl/mail.$domain.ca" ]; then
+    ca=$(cat $USER_DATA/ssl/mail.$domain.ca |sed ':a;N;$!ba;s/\n/\\n/g')
+fi
+
+# Listing data
+case $format in
+    json)   json_list ;;
+    plain)  plain_list ;;
+    csv)    csv_list ;;
+    shell)  shell_list ;;
+esac
+
+
+#----------------------------------------------------------#
+#                       Hestia                              #
+#----------------------------------------------------------#
+
+exit

+ 7 - 6
bin/v-list-mail-domains

@@ -31,6 +31,7 @@ json_list() {
         "CATCHALL": "'$CATCHALL'",
         "ACCOUNTS": "'$ACCOUNTS'",
         "U_DISK": "'$U_DISK'",
+        "SSL": "'$SSL'",
         "SUSPENDED": "'$SUSPENDED'",
         "TIME": "'$TIME'",
         "DATE": "'$DATE'"
@@ -48,11 +49,11 @@ json_list() {
 # SHELL list function
 shell_list() {
     IFS=$'\n'
-    echo "DOMAIN   ANTIVIRUS   ANTISPAM   DKIM  ACC   DISK   SPND   DATE"
-    echo "------   ---------   --------   ----  ---   ----   ---   ----"
+    echo "DOMAIN   ANTIVIRUS   ANTISPAM   DKIM  SSL   ACC   DISK   SPND   DATE"
+    echo "------   ---------   --------   ----  ---   ---   ----   ---   ----"
     while read str; do
         eval $str
-        echo -n "$DOMAIN $ANTIVIRUS $ANTISPAM $DKIM $ACCOUNTS $U_DISK "
+        echo -n "$DOMAIN $ANTIVIRUS $ANTISPAM $DKIM $SSL $ACCOUNTS $U_DISK "
         echo "$SUSPENDED $DATE"
     done < <(cat $USER_DATA/mail.conf)
 }
@@ -62,7 +63,7 @@ plain_list() {
     IFS=$'\n'
     while read str; do
         eval $str
-        echo -ne "$DOMAIN\t$ANTIVIRUS\t$ANTISPAM\t$DKIM\t$CATCHALL\t"
+        echo -ne "$DOMAIN\t$ANTIVIRUS\t$ANTISPAM\t$DKIM\t$SSL\$CATCHALL\t"
         echo -e "$ACCOUNTS\t$U_DISK\t$SUSPENDED\t$TIME\t$DATE"
     done < <(cat $USER_DATA/mail.conf)
 }
@@ -70,11 +71,11 @@ plain_list() {
 # CSV list function
 csv_list() {
     IFS=$'\n'
-    echo -n "DOMAIN,ANTIVIRUS,ANTISPAM,DKIM,CATCHALL,ACCOUNTS,U_DISK,"
+    echo -n "DOMAIN,ANTIVIRUS,ANTISPAM,DKIM,SSL,CATCHALL,ACCOUNTS,U_DISK,"
     echo "SUSPENDED,TIME,DATE"
     while read str; do
         eval $str
-        echo -n "$DOMAIN,$ANTIVIRUS,$ANTISPAM,$DKIM,$CATCHALL,$ACCOUNTS,"
+        echo -n "$DOMAIN,$ANTIVIRUS,$ANTISPAM,$DKIM,$SSL,$CATCHALL,$ACCOUNTS,"
         echo "'$U_DISK,$SUSPENDED,$TIME,$DATE"
         echo
     done < <(cat $USER_DATA/mail.conf)

+ 2 - 2
bin/v-list-sys-hestia-autoupdate

@@ -39,7 +39,7 @@ fi
 
 # Reset counters
 U_MAIL_DOMAINS=0
-U_MAIL_DKMI=0
+U_MAIL_DKIM=0
 U_MAIL_ACCOUNTS=0
 SUSPENDED_MAIL=0
 U_DISK_MAIL=0
@@ -62,7 +62,7 @@ done
 
 # Updating counters
 update_user_value "$user" '$U_MAIL_DOMAINS' "$U_MAIL_DOMAINS"
-update_user_value "$user" '$U_MAIL_DKMI' "$U_MAIL_DKMI"
+update_user_value "$user" '$U_MAIL_DKIM' "$U_MAIL_DKIM"
 update_user_value "$user" '$U_MAIL_ACCOUNTS' "$U_MAIL_ACCOUNTS"
 update_user_value "$user" '$SUSPENDED_MAIL' "$SUSPENDED_MAIL"
 update_user_value "$user" '$U_DISK_MAIL' "$U_DISK_MAIL"

+ 73 - 0
bin/v-update-sys-hestia

@@ -562,6 +562,79 @@ is_mail_new() {
 }
 
 
+# Add mail server SSL configuration
+add_mail_ssl_config() {
+     # Ensure that SSL certificate directories exists
+    if [ ! -d $HOMEDIR/$user/conf/mail/$domain/ssl/ ]; then
+        mkdir -p $HOMEDIR/$user/conf/mail/$domain/ssl/
+    fi
+
+    if [ ! -d /usr/local/hestia/ssl/mail ]; then
+        mkdir -p /usr/local/hestia/ssl/mail
+    fi
+
+    if [ ! -d /etc/dovecot/conf.d/domains ]; then
+        mkdir -p /etc/dovecot/conf.d/domains
+    fi
+
+    # Add certificate to Hestia user configuration data directory
+    cp -f $ssl_dir/$domain.crt $USER_DATA/ssl/mail.$domain.crt
+    cp -f $ssl_dir/$domain.key $USER_DATA/ssl/mail.$domain.key
+    cp -f $ssl_dir/$domain.crt $USER_DATA/ssl/mail.$domain.pem
+    if [ -e "$ssl_dir/$domain.ca" ]; then
+        cp -f $ssl_dir/$domain.ca $USER_DATA/ssl/mail.$domain.ca
+        echo >> $USER_DATA/ssl/mail.$domain.pem
+        cat $USER_DATA/ssl/mail.$domain.ca >> $USER_DATA/ssl/mail.$domain.pem
+    fi
+
+    chmod 660 $USER_DATA/ssl/mail.$domain.*
+
+    # Add certificate to user home directory
+    cp -f $USER_DATA/ssl/mail.$domain.crt $HOMEDIR/$user/conf/mail/$domain/ssl/$domain.crt
+    cp -f $USER_DATA/ssl/mail.$domain.key $HOMEDIR/$user/conf/mail/$domain/ssl/$domain.key
+    cp -f $USER_DATA/ssl/mail.$domain.pem $HOMEDIR/$user/conf/mail/$domain/ssl/$domain.pem
+    if [ -e "$USER_DATA/ssl/mail.$domain.ca" ]; then
+        cp -f $USER_DATA/ssl/mail.$domain.ca $HOMEDIR/$user/conf/mail/$domain/ssl/$domain.ca
+    fi
+
+    # Add domain SSL configuration to dovecot
+    if [ -f /etc/dovecot/conf.d/domains/$domain.conf ]; then
+        rm -f /etc/dovecot/conf.d/domains/$domain.conf
+    fi
+    
+    echo "" >> /etc/dovecot/conf.d/domains/$domain.conf
+    echo "local_name mail.$domain {" >> /etc/dovecot/conf.d/domains/$domain.conf
+    echo "  ssl_cert = <$HOMEDIR/$user/conf/mail/$domain/ssl/$domain.pem" >> /etc/dovecot/conf.d/domains/$domain.conf
+    echo "  ssl_key = <$HOMEDIR/$user/conf/mail/$domain/ssl/$domain.key" >> /etc/dovecot/conf.d/domains/$domain.conf
+    echo "}" >> /etc/dovecot/conf.d/domains/$domain.conf
+
+    # Add domain SSL configuration to exim4
+    ln -s $HOMEDIR/$user/conf/mail/$domain/ssl/$domain.pem /usr/local/hestia/ssl/mail/mail.$domain.crt
+    ln -s $HOMEDIR/$user/conf/mail/$domain/ssl/$domain.key /usr/local/hestia/ssl/mail/mail.$domain.key
+
+    # Set correct permissions on certificates
+    chmod 0644 $HOMEDIR/$user/conf/mail/$domain/ssl/*
+    chown -h $user:mail $HOMEDIR/$user/conf/mail/$domain/ssl/*
+    chmod -R 0644 /usr/local/hestia/ssl/mail/*
+    chown -h $user:mail /usr/local/hestia/ssl/mail/*
+}
+
+# Delete SSL support for mail domain
+del_mail_ssl_config() {
+    # Remove dovecot configuration
+    rm -f /etc/dovecot/conf.d/domains/mail.$domain.conf
+
+    # Remove SSL vhost configuration
+    rm -f $HOMEDIR/$user/conf/mail/$domain/*.ssl.conf
+    rm -f /etc/$WEB_SYSTEM/conf.d/domains/$WEBMAIL_ALIAS.$domain.ssl.conf
+    rm -f /etc/$PROXY_SYSTEM/conf.d/domains/$WEBMAIL_ALIAS.$domain.ssl.conf
+
+    # Remove SSL certificates
+    rm -f $HOMEDIR/$user/conf/mail/$domain/ssl/*
+    rm -f $USER_DATA/ssl/mail.$domain.*
+    rm -f /usr/local/hestia/ssl/mail/mail.$domain.*
+}
+
 #----------------------------------------------------------#
 #                        CMN                               #
 #----------------------------------------------------------#

+ 6 - 0
func/rebuild.sh

@@ -529,6 +529,12 @@ rebuild_mail_domain_conf() {
             chown -R dovecot:mail $HOMEDIR/$user/conf/mail/$domain/passwd
         fi
         chown $user:mail $HOMEDIR/$user/mail/$domain_idn
+        # Remove and recreate SSL configuration
+            if [ "$SSL" = 'yes' ]; then
+                mkdir -p $HOMEDIR/$user/conf/mail/$domain/ssl/
+                del_mail_ssl_config
+                add_mail_ssl_config
+            fi
     fi
 
     # Update counters

+ 4 - 0
install/deb/dovecot/conf.d/10-mail.conf

@@ -2,3 +2,7 @@ mail_privileged_group = mail
 mail_access_groups = mail
 mail_location = maildir:%h/mail/%d/%n
 pop3_uidl_format = %08Xu%08Xv
+
+mailbox_list_index = yes
+mailbox_idle_check_interval = 30 secs
+maildir_copy_with_hardlinks = yes

+ 3 - 3
install/deb/dovecot/dovecot.conf

@@ -37,8 +37,8 @@ namespace {
     }
 
     mailbox Junk {
-        special_use = \Junk
         auto = no
+        special_use = \Junk
     }
 
     mailbox Sent {
@@ -47,12 +47,12 @@ namespace {
     }
 
     mailbox "Sent Mail" {
-        special_use = \Sent
         auto = no
+        special_use = \Sent
     }
     
     mailbox "Sent Messages" {
-        special_use = \Sent
         auto = no
+        special_use = \Sent
     }
 }

+ 27 - 5
install/deb/exim/exim4.conf.template

@@ -8,7 +8,7 @@
 #SPAM_SCORE = 50
 #CLAMD = yes
 
-smtp_banner = $smtp_active_hostname \
+smtp_banner = $smtp_active_hostname
 add_environment = <; PATH=/bin:/usr/bin
 keep_environment =
 disable_ipv6 = true
@@ -34,9 +34,31 @@ spamd_address = 127.0.0.1 783
 av_scanner = clamd: /var/run/clamav/clamd.ctl
 .endif
 
+log_selector = +tls_sni
+
 tls_advertise_hosts = *
-tls_certificate = /usr/local/hestia/ssl/certificate.crt
-tls_privatekey = /usr/local/hestia/ssl/certificate.key
+
+# here we test that $tls_in_sni really is a domain, but constructing an arbitrary email address foo@...
+# and then extracting the domain with a function that should fails if the email address is not valid
+# then we looks to see that the cert exists, and use it
+# otherwise we use the default cert in /etc/ssl
+tls_certificate = \
+        ${if and {\
+                     { eq {${domain:foo@$tls_in_sni}} {$tls_in_sni}}\
+                     { exists{/usr/local/hestia/ssl/mail/$tls_in_sni.crt} }\
+                 }\
+                 {/usr/local/hestia/ssl/mail/$tls_in_sni.crt}\
+                 {/usr/local/hestia/ssl/certificate.crt}\
+         }
+
+tls_privatekey = \
+        ${if and {\
+                     { eq {${domain:foo@$tls_in_sni}} {$tls_in_sni}}\
+                     { exists{/usr/local/hestia/ssl/mail/$tls_in_sni.key} }\
+                 }\
+                 {/usr/local/hestia/ssl/mail/$tls_in_sni.key}\
+                 {/usr/local/hestia/ssl/certificate.key}\
+         }
 
 daemon_smtp_ports = 25 : 465 : 587
 tls_on_connect_ports = 465
@@ -86,7 +108,7 @@ acl_check_mail:
   deny    condition     = ${if eq{$sender_helo_name}{}}
           message       = HELO required before MAIL
 
-  drop    message       = Helo name contains a ip address (HELO was $sender_helo_name) and not is valid
+  drop    message       = Helo name contains an IP address (HELO was $sender_helo_name) and not is valid
           condition     = ${if match{$sender_helo_name}{\N((\d{1,3}[.-]\d{1,3}[.-]\d{1,3}[.-]\d{1,3})|([0-9a-f]{8})|([0-9A-F]{8}))\N}{yes}{no}}
           condition     = ${if match {${lookup dnsdb{>: defer_never,ptr=$sender_host_address}}\}{$sender_helo_name}{no}{yes}}
           delay         = 45s
@@ -303,7 +325,7 @@ begin transports
 
 remote_smtp:
   driver = smtp
-  #helo_data = $sender_address_domain
+  helo_data = mail.$sender_address_domain
   dkim_domain = DKIM_DOMAIN
   dkim_selector = mail
   dkim_private_key = DKIM_PRIVATE_KEY

+ 24 - 0
install/upgrade/0.9.8-29.sh

@@ -159,6 +159,29 @@ if [ -f /etc/dovecot/dovecot.conf ]; then
     sleep 0.5
 fi
 
+# Update user information for mail domain SSL configuration
+userlist=$(ls --sort=time $HESTIA/data/users/)
+for user in $userlist; do
+    USER_DATA="$HESTIA/data/users/$user"
+    # Update user counter if SSL variable doesn't exist
+    if [ -z "$(grep "U_MAIL_SSL" $USER_DATA/user.conf)" ]; then
+        echo "(*) Adding missing variable for per-domain mail SSL..."
+        echo "U_MAIL_SSL='0'" >> $USER_DATA/user.conf
+    fi
+
+    # Update mail configuration file
+    conf="$USER_DATA/mail.conf"
+    while read line ; do
+        eval $line
+        
+        add_object_key "mail" 'DOMAIN' "$DOMAIN" 'SSL' 'SUSPENDED'
+        update_object_value 'mail' 'DOMAIN' "$DOMAIN" '$SSL' 'no'
+        
+        add_object_key "mail" 'DOMAIN' "$DOMAIN" 'LETSENCRYPT' 'SUSPENDED'
+        update_object_value 'mail' 'DOMAIN' "$DOMAIN" '$LETSENCRYPT' 'no'
+    done < $conf
+done
+
 # Add IMAP system variable to configuration if dovecot is installed
 if [ -z "$IMAP_SYSTEM" ]; then 
     if [ -f /usr/bin/dovecot ]; then
@@ -173,6 +196,7 @@ for user in `ls /usr/local/hestia/data/users/`; do
     v-rebuild-mail-domains $user
 done
 
+
 # Remove Webalizer and replace it with awstats as default
 echo "(*) Setting awstats as default web statistics backend..."
 apt purge webalizer -y > /dev/null 2>&1

+ 180 - 0
web/edit/mail/index.php

@@ -39,6 +39,25 @@ if ((!empty($_GET['domain'])) && (empty($_GET['account'])))  {
     } else {
         $v_status =  'active';
     }
+    
+    $v_ssl = $data[$v_domain]['SSL'];
+    if (!empty($v_ssl)) {
+        exec (HESTIA_CMD."v-list-mail-domain-ssl ".$user." '".$v_domain."' json", $output, $return_var);
+        $ssl_str = json_decode(implode('', $output), true);
+        unset($output);
+        $v_ssl_crt = $ssl_str[$v_domain]['CRT'];
+        $v_ssl_key = $ssl_str[$v_domain]['KEY'];
+        $v_ssl_ca = $ssl_str[$v_domain]['CA'];
+        $v_ssl_subject = $ssl_str[$v_domain]['SUBJECT'];
+        $v_ssl_aliases = $ssl_str[$v_domain]['ALIASES'];
+        $v_ssl_not_before = $ssl_str[$v_domain]['NOT_BEFORE'];
+        $v_ssl_not_after = $ssl_str[$v_domain]['NOT_AFTER'];
+        $v_ssl_signature = $ssl_str[$v_domain]['SIGNATURE'];
+        $v_ssl_pub_key = $ssl_str[$v_domain]['PUB_KEY'];
+        $v_ssl_issuer = $ssl_str[$v_domain]['ISSUER'];
+    }
+    $v_letsencrypt = $data[$v_domain]['LETSENCRYPT'];
+    if (empty($v_letsencrypt)) $v_letsencrypt = 'no';
 }
 
 // List mail account
@@ -164,6 +183,167 @@ if ((!empty($_POST['save'])) && (!empty($_GET['domain'])) && (empty($_GET['accou
         check_return_code($return_var,$output);
         unset($output);
     }
+    
+    // Change SSL certificate
+    if (( $v_letsencrypt == 'no' ) && (empty($_POST['v_letsencrypt'])) && ( $v_ssl == 'yes' ) && (!empty($_POST['v_ssl'])) && (empty($_SESSION['error_msg']))) {
+        if (( $v_ssl_crt != str_replace("\r\n", "\n",  $_POST['v_ssl_crt'])) || ( $v_ssl_key != str_replace("\r\n", "\n",  $_POST['v_ssl_key'])) || ( $v_ssl_ca != str_replace("\r\n", "\n",  $_POST['v_ssl_ca']))) {
+            exec ('mktemp -d', $mktemp_output, $return_var);
+            $tmpdir = $mktemp_output[0];
+
+            // Certificate
+            if (!empty($_POST['v_ssl_crt'])) {
+                $fp = fopen($tmpdir."/".$_POST['v_domain'].".crt", 'w');
+                fwrite($fp, str_replace("\r\n", "\n",  $_POST['v_ssl_crt']));
+                fwrite($fp, "\n");
+                fclose($fp);
+            }
+
+            // Key
+            if (!empty($_POST['v_ssl_key'])) {
+                $fp = fopen($tmpdir."/".$_POST['v_domain'].".key", 'w');
+                fwrite($fp, str_replace("\r\n", "\n", $_POST['v_ssl_key']));
+                fwrite($fp, "\n");
+                fclose($fp);
+            }
+
+            // CA
+            if (!empty($_POST['v_ssl_ca'])) {
+                $fp = fopen($tmpdir."/".$_POST['v_domain'].".ca", 'w');
+                fwrite($fp, str_replace("\r\n", "\n", $_POST['v_ssl_ca']));
+                fwrite($fp, "\n");
+                fclose($fp);
+            }
+
+            exec (HESTIA_CMD."v-change-mail-domain-sslcert ".$user." ".$v_domain." ".$tmpdir." 'no'", $output, $return_var);
+            check_return_code($return_var,$output);
+            unset($output);
+            $restart_web = 'yes';
+            $restart_proxy = 'yes';
+
+            exec (HESTIA_CMD."v-list-mail-domain-ssl ".$user." '".$v_domain."' json", $output, $return_var);
+            $ssl_str = json_decode(implode('', $output), true);
+            unset($output);
+            $v_ssl_crt = $ssl_str[$v_domain]['CRT'];
+            $v_ssl_key = $ssl_str[$v_domain]['KEY'];
+            $v_ssl_ca = $ssl_str[$v_domain]['CA'];
+            $v_ssl_subject = $ssl_str[$v_domain]['SUBJECT'];
+            $v_ssl_aliases = $ssl_str[$v_domain]['ALIASES'];
+            $v_ssl_not_before = $ssl_str[$v_domain]['NOT_BEFORE'];
+            $v_ssl_not_after = $ssl_str[$v_domain]['NOT_AFTER'];
+            $v_ssl_signature = $ssl_str[$v_domain]['SIGNATURE'];
+            $v_ssl_pub_key = $ssl_str[$v_domain]['PUB_KEY'];
+            $v_ssl_issuer = $ssl_str[$v_domain]['ISSUER'];
+
+            // Cleanup certificate tempfiles
+            if (!empty($_POST['v_ssl_crt'])) unlink($tmpdir."/".$_POST['v_domain'].".crt");
+            if (!empty($_POST['v_ssl_key'])) unlink($tmpdir."/".$_POST['v_domain'].".key");
+            if (!empty($_POST['v_ssl_ca']))  unlink($tmpdir."/".$_POST['v_domain'].".ca");
+            rmdir($tmpdir);
+        }
+    }
+
+    // Delete Lets Encrypt support
+    if (( $v_letsencrypt == 'yes' ) && (empty($_POST['v_letsencrypt'])) && (empty($_SESSION['error_msg']))) {
+        exec (HESTIA_CMD."v-delete-letsencrypt-mail-domain ".$user." ".$v_domain." 'no'", $output, $return_var);
+        check_return_code($return_var,$output);
+        unset($output);
+        $v_ssl_crt = '';
+        $v_ssl_key = '';
+        $v_ssl_ca = '';
+        $v_letsencrypt = 'no';
+        $v_letsencrypt_deleted = 'yes';
+        $v_ssl = 'no';
+        $restart_mail = 'yes';
+    }
+
+    // Delete SSL certificate
+    if (( $v_ssl == 'yes' ) && (empty($_POST['v_ssl'])) && (empty($_SESSION['error_msg']))) {
+        exec (HESTIA_CMD."v-delete-mail-domain-ssl ".$v_username." ".$v_domain." 'no'", $output, $return_var);
+        check_return_code($return_var,$output);
+        unset($output);
+        $v_ssl_crt = '';
+        $v_ssl_key = '';
+        $v_ssl_ca = '';
+        $v_ssl = 'no';
+        $restart_mail = 'yes';
+    }
+
+    // Add Lets Encrypt support
+    if ((!empty($_POST['v_ssl'])) && ( $v_letsencrypt == 'no' ) && (!empty($_POST['v_letsencrypt'])) && empty($_SESSION['error_msg'])) {
+        $l_aliases = 'mail.' . $v_domain;
+        exec (HESTIA_CMD."v-add-letsencrypt-mail-domain ".$user." ".$v_domain." '".$l_aliases."' 'no'", $output, $return_var);
+        check_return_code($return_var,$output);
+        unset($output);
+        $v_letsencrypt = 'yes';
+        $v_ssl = 'yes';
+        $restart_mail = 'yes';
+     }
+
+     // Add SSL certificate
+     if (( $v_ssl == 'no' ) && (!empty($_POST['v_ssl']))  && (empty($v_letsencrypt_deleted)) && (empty($_SESSION['error_msg']))) {
+        if (empty($_POST['v_ssl_crt'])) $errors[] = 'ssl certificate';
+        if (empty($_POST['v_ssl_key'])) $errors[] = 'ssl key';
+        if (!empty($errors[0])) {
+            foreach ($errors as $i => $error) {
+                if ( $i == 0 ) {
+                    $error_msg = $error;
+                } else {
+                    $error_msg = $error_msg.", ".$error;
+                }
+            }
+            $_SESSION['error_msg'] = __('Field "%s" can not be blank.',$error_msg);
+        } else {
+            exec ('mktemp -d', $mktemp_output, $return_var);
+            $tmpdir = $mktemp_output[0];
+
+            // Certificate
+            if (!empty($_POST['v_ssl_crt'])) {
+                $fp = fopen($tmpdir."/".$_POST['v_domain'].".crt", 'w');
+                fwrite($fp, str_replace("\r\n", "\n", $_POST['v_ssl_crt']));
+                fclose($fp);
+            }
+
+            // Key
+            if (!empty($_POST['v_ssl_key'])) {
+                $fp = fopen($tmpdir."/".$_POST['v_domain'].".key", 'w');
+                fwrite($fp, str_replace("\r\n", "\n", $_POST['v_ssl_key']));
+                fclose($fp);
+            }
+
+            // CA
+            if (!empty($_POST['v_ssl_ca'])) {
+                $fp = fopen($tmpdir."/".$_POST['v_domain'].".ca", 'w');
+                fwrite($fp, str_replace("\r\n", "\n", $_POST['v_ssl_ca']));
+                fclose($fp);
+            }
+            exec (HESTIA_CMD."v-add-mail-domain-ssl ".$user." ".$v_domain." ".$tmpdir." 'no'", $output, $return_var);
+            check_return_code($return_var,$output);
+            unset($output);
+            $v_ssl = 'yes';
+            $restart_web = 'yes';
+            $restart_proxy = 'yes';
+
+            exec (HESTIA_CMD."v-list-mail-domain-ssl ".$user." '".$v_domain."' json", $output, $return_var);
+            $ssl_str = json_decode(implode('', $output), true);
+            unset($output);
+            $v_ssl_crt = $ssl_str[$_POST['v_domain']]['CRT'];
+            $v_ssl_key = $ssl_str[$_POST['v_domain']]['KEY'];
+            $v_ssl_ca = $ssl_str[$_POST['v_domain']]['CA'];
+            $v_ssl_subject = $ssl_str[$_POST['v_domain']]['SUBJECT'];
+            $v_ssl_aliases = $ssl_str[$_POST['v_domain']]['ALIASES'];
+            $v_ssl_not_before = $ssl_str[$_POST['v_domain']]['NOT_BEFORE'];
+            $v_ssl_not_after = $ssl_str[$_POST['v_domain']]['NOT_AFTER'];
+            $v_ssl_signature = $ssl_str[$_POST['v_domain']]['SIGNATURE'];
+            $v_ssl_pub_key = $ssl_str[$_POST['v_domain']]['PUB_KEY'];
+            $v_ssl_issuer = $ssl_str[$_POST['v_domain']]['ISSUER'];
+
+            // Cleanup certificate tempfiles
+            if (!empty($_POST['v_ssl_crt'])) unlink($tmpdir."/".$_POST['v_domain'].".crt");
+            if (!empty($_POST['v_ssl_key'])) unlink($tmpdir."/".$_POST['v_domain'].".key");
+            if (!empty($_POST['v_ssl_ca'])) unlink($tmpdir."/".$_POST['v_domain'].".ca");
+            rmdir($tmpdir);
+        }
+    }
 
     // Set success message
     if (empty($_SESSION['error_msg'])) {

+ 115 - 0
web/templates/admin/edit_mail.html

@@ -81,6 +81,121 @@
                                     <label><input type="checkbox" size="20" class="vst-checkbox" name="v_dkim" <?php if ($v_dkim == 'yes') echo "checked=yes"; ?>> <?php print __('DKIM Support');?></label>
                                 </td>
                             </tr>
+                            <tr>
+                                <td class="vst-text step-top">
+                                    <label><input type="checkbox" size="20" class="vst-checkbox" name="v_ssl" <?php if ($v_ssl == 'yes') echo "checked=yes" ?> onclick="javascript:elementHideShow('ssltable');"> <?php print __('SSL Support');?></label>
+                                </td>
+                            </tr>
+                            <tr>
+                                <td class="step-left">
+                                    <table style="display:<?php if ($v_ssl == 'no' ) { echo 'none';} else {echo 'block';}?> ;" id="ssltable">
+                                        <tr>
+                                            <td class="input-label vst-text">
+                                                <label><input type="checkbox" size="20" class="vst-checkbox" name="v_letsencrypt" <?php if($v_letsencrypt == 'yes' || $v_letencrypt == 'on') echo "checked=yes" ?> onclick="App.Actions.WEB.toggle_letsencrypt(this)"> <?php print __('Lets Encrypt Support');?></label>
+                                            </td>
+                                        </tr>
+                                      
+                                        <tr>
+                                            <td class="vst-text input-label">
+                                                <?php print __('SSL Certificate');?>
+                                                <span id="generate-csr"> / <a class="generate" target="_blank" href="/generate/ssl/?domain=<?=$v_domain?>"><?=__('Generate CSR')?></a></span>
+                                            </td>
+                                        </tr>
+                                        <tr>
+                                            <td>
+                                                <textarea size="20" class="vst-textinput" name="v_ssl_crt"><?=htmlentities(trim($v_ssl_crt, "'"))?></textarea>
+                                            </td>
+                                        </tr>
+                                        <tr>
+                                            <td class="vst-text input-label">
+                                                <?php print __('SSL Key');?>
+                                            </td>
+                                        </tr>
+                                        <tr>
+                                            <td>
+                                                <textarea size="20" class="vst-textinput" name="v_ssl_key"><?=htmlentities(trim($v_ssl_key, "'"))?></textarea>
+                                            </td>
+                                        </tr>
+                                        <tr>
+                                            <td class="vst-text input-label">
+                                                <?php print __('SSL Certificate Authority / Intermediate');?> <span class="optional">(<?php print __('optional');?>)</span>
+                                            </td>
+                                        </tr>
+                                        <tr>
+                                            <td>
+                                                <textarea size="20" class="vst-textinput" name="v_ssl_ca"><?=htmlentities(trim($v_ssl_ca, "'"))?></textarea>
+                                            </td>
+                                        </tr>
+                                        <?
+                                        if ($v_ssl != 'no' ) { ?>
+                                            <tr>
+                                                <td>
+                                                    <table class="additional-info">
+                                                        <tr>
+                                                            <td>
+                                                                <?=__('SUBJECT')?>:
+                                                            </td>
+                                                            <td class="details">
+                                                                <?=$v_ssl_subject?>
+                                                            </td>
+                                                        </tr>
+                                                        <? if($v_ssl_aliases){?>
+                                                            <tr>
+                                                                <td>
+                                                                    <?=__('ALIASES')?>:
+                                                                </td>
+                                                                <td class="details">
+                                                                    <?=$v_ssl_aliases?>
+                                                                </td>
+                                                            </tr>
+                                                        <? } ?>
+                                                        <tr>
+                                                            <td>
+                                                                <?=__('NOT_BEFORE')?>:
+                                                            </td>
+                                                            <td class="details">
+                                                                <?=$v_ssl_not_before?>
+                                                            </td>
+                                                        </tr>
+                                                        <tr>
+                                                            <td>
+                                                                <?=__('NOT_AFTER')?>:
+                                                            </td>
+                                                            <td class="details">
+                                                                <?=$v_ssl_not_after?>
+                                                            </td>
+                                                        </tr>
+                                                        <tr>
+                                                            <td>
+                                                                <?=__('SIGNATURE')?>:
+                                                            </td>
+                                                            <td class="details">
+                                                                <?=$v_ssl_signature?>
+                                                            </td>
+                                                        </tr>
+                                                        <tr>
+                                                            <td>
+                                                                <?=__('PUB_KEY')?>:
+                                                            </td>
+                                                            <td class="details">
+                                                                <?=$v_ssl_pub_key?>
+                                                            </td>
+                                                        </tr>
+                                                        <tr>
+                                                            <td>
+                                                                <?=__('ISSUER')?>
+                                                            </td>
+                                                            <td class="details">
+                                                                <?=$v_ssl_issuer?>
+                                                            </td>
+                                                        </tr>
+                                                    </table>
+                                                </td>
+                                            </tr>
+                                        <? } // if ssl is enabled ?>
+                                    </table>
+                                </td>
+                            </tr>
                         </table>
                         <table class="data-col2">
                             <tr>

+ 1 - 1
web/templates/admin/edit_mail_acc.html

@@ -205,7 +205,7 @@
                         </tr>
                         <?
                             list($http_host, $port) = explode(':', $_SERVER["HTTP_HOST"].":");
-                            $webmail = "http://".$http_host."/webmail/";
+                            $webmail = "http://mail.".$http_host."/";
                             if (!empty($_SESSION['MAIL_URL'])) $webmail = $_SESSION['MAIL_URL'];
                         ?>
                         <tr>

+ 26 - 8
web/templates/admin/list_mail.html

@@ -14,7 +14,7 @@
               <td class="step-right">
                 <?
                   list($http_host, $port) = explode(':', $_SERVER["HTTP_HOST"].":");
-                  $webmail = "http://".$http_host."/webmail/";
+                  $webmail = "http://mail.".$http_host."/";
                   if (!empty($_SESSION['MAIL_URL'])) $webmail = $_SESSION['MAIL_URL'];
                 ?>
                 <a class="vst" href="<?=$webmail?>" target="_blank"><?=__('open webmail')?> <i></i></a>
@@ -67,19 +67,21 @@
           
                 <div class="l-unit__col l-unit__col--right step-top table-header">
                   <div style="margin-bottom: 40px;">
-                      <div class="clearfix l-unit__stat-col--left wide-3"><b><?php print __('Domain');?></b></div>
-                      <div class="clearfix l-unit__stat-col--left text-center"><b><?php print __('Accounts');?></b></div>
-                      <div class="clearfix l-unit__stat-col--left text-center"><b><?php print __('Disk');?></b></div>
+                      <div class="clearfix l-unit__stat-col--left wide-2"><b><?php print __('Domain');?></b></div>
+                      <div class="clearfix l-unit__stat-col--left text-center compact"><b><?php print __('Accounts');?></b></div>
+                      <div class="clearfix l-unit__stat-col--left text-center compact"><b><?php print __('Disk');?></b></div>
+                      <div class="clearfix l-unit__stat-col--left text-center compact-3"><b><?php print __('Webmail');?></b></div>
                       <div class="clearfix l-unit__stat-col--left text-center compact-3"><b><?php print __('Antivirus');?></b></div>
                       <div class="clearfix l-unit__stat-col--left text-center compact-3"><b><?php print __('AntiSpam');?></b></div>
                       <div class="clearfix l-unit__stat-col--left text-center compact-3"><b><?php print __('DKIM');?></b></div>
+                      <div class="clearfix l-unit__stat-col--left text-center compact-3"><b><?php print __('SSL');?></b></div>
                   </div>
                 </div>
               </div>
 
       <?
         list($http_host, $port) = explode(':', $_SERVER["HTTP_HOST"].":");
-        $webmail = "http://".$http_host."/webmail/";
+        $webmail = "http://mail.".$http_host."/";
         if (!empty($_SESSION['MAIL_URL'])) $webmail = $_SESSION['MAIL_URL'];
 
         foreach ($data as $key => $value) {
@@ -144,17 +146,25 @@ sort-accounts="<?=$data[$key]['ACCOUNTS']?>" sort-star="<? if($_SESSION['favouri
                       <input id="check<?php echo $i ?>" class="ch-toggle" type="checkbox" name="domain[]" value="<?php echo $key ?>">
                       <label for="check<?php echo $i ?>" class="check-label"></label>
                     </div>
-                  <div class="clearfix l-unit__stat-col--left wide-3"><b><?=$key?></b></div>
-                  <div class="clearfix l-unit__stat-col--left text-center"><b>
+                  <div class="clearfix l-unit__stat-col--left wide-2"><b><?=$key?></b></div>
+                  <div class="clearfix l-unit__stat-col--left text-center compact"><b>
                     <? if($data[$key]['ACCOUNTS']) { echo '<span>'.$data[$key]['ACCOUNTS'].'</span>'; ?>
                     <? } else {?>
                       <span>0</span>
                     <? } ?>
                     </b>
                   </div>
-                  <div class="clearfix l-unit__stat-col--left text-center"><b>
+                  <div class="clearfix l-unit__stat-col--left text-center compact"><b>
                     <?=humanize_usage_size($data[$key]['U_DISK'])?></b> <span class="text-small"><?=humanize_usage_measure($data[$key]['U_DISK'])?></span>
                   </div>
+                  <div class="clearfix l-unit__stat-col--left text-center compact-3"><b>
+                    <? if($data[$key]['WEBMAIL'] == 'no'){ ?>
+                      <i class="fas fa-minus-circle"></i>
+                    <? } else {?>
+                      <i class="fas fa-check-circle status-icon-green"></i>
+                    <? } ?>
+                  </b>
+                 </div>
                   <div class="clearfix l-unit__stat-col--left text-center compact-3"><b>
                       <? if($data[$key]['ANTIVIRUS'] == 'no'){ ?>
                         <i class="fas fa-times-circle" style="color: red;"></i>
@@ -179,6 +189,14 @@ sort-accounts="<?=$data[$key]['ACCOUNTS']?>" sort-star="<? if($_SESSION['favouri
                       <? } ?>
                     </b>
                   </div>
+                  <div class="clearfix l-unit__stat-col--left text-center compact-3"><b>
+                      <? if($data[$key]['SSL'] == 'no'){ ?>
+                        <i class="fas fa-times-circle" style="color: red;"></i>
+                      <? } else {?>
+                        <i class="fas fa-check-circle status-icon-green"></i>
+                      <? } ?>
+                    </b>
+                  </div>
               </div>
             </div>
         <!-- /.l-unit__col -->

+ 3 - 0
web/templates/admin/list_mail_acc.html

@@ -56,6 +56,9 @@
     <div class="l-separator"></div>
     <!-- /.l-separator -->
     <div class="l-center units animated fadeIn">
+        <div class="l-unit header">
+            <div class="subtitle"><?=__('Listing')?>  <?=htmlentities($_GET['domain'])?></div>
+        </div>
         <div class="l-unit header">
             <div class="l-unit__col l-unit__col--left clearfix">
               <div class="text-center jump-small-top"></div>