Просмотр исходного кода

Let's Encrypt v2 with wildcard support

Serghey Rodin 7 лет назад
Родитель
Сommit
f8b4d42b74

+ 182 - 65
bin/v-add-letsencrypt-domain

@@ -1,13 +1,8 @@
 #!/bin/bash
-# info: adding letsencrypt ssl cetificate for domain
-# options: USER DOMAIN [ALIASES] [RESTART] [NOTIFY]
+# info: check letsencrypt domain
+# options: USER DOMAIN [ALIASES]
 #
-# The function turns on SSL support for a domain. Parameter ssl_dir is a path
-# to directory where 2 or 3 ssl files can be found. Certificate file
-# domain.tld.crt and its key domain.tld.key  are mandatory. Certificate
-# authority domain.tld.ca file is optional. If home directory  parameter
-# (ssl_home) is not set, https domain uses public_shtml as separate
-# documentroot directory.
+# The function check and validates domain with Let's Encript
 
 
 #----------------------------------------------------------#
@@ -18,39 +13,67 @@
 user=$1
 domain=$2
 aliases=$3
-restart=$4
-notify=$5
+
+# LE API
+API='https://acme-v02.api.letsencrypt.org'
 
 # Includes
 source $VESTA/func/main.sh
 source $VESTA/func/domain.sh
 source $VESTA/conf/vesta.conf
 
-# Additional argument formatting
-format_domain_idn
+# 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'
+check_args '2' "$#" 'USER DOMAIN [ALIASES]'
+is_format_valid 'user' 'domain' 'aliases'
 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 'web' 'DOMAIN' "$domain"
 is_object_unsuspended 'web' 'DOMAIN' "$domain"
+get_domain_values 'web'
+for alias in $(echo "$aliases" |tr ',' '\n' |sort -u); do
+    check_alias="$(echo $ALIAS |tr ',' '\n' |grep ^$alias$)"
+    if [ -z "$check_alias" ]; then
+        check_result $E_NOTEXIST "domain alias $alias doesn't exist"
+    fi
+done
 
 
 #----------------------------------------------------------#
 #                       Action                             #
 #----------------------------------------------------------#
 
-# Parsing domain data
-get_domain_values 'web'
-
 # Registering LetsEncrypt user account
 $BIN/v-add-letsencrypt-user $user
 if [ "$?" -ne 0  ]; then
@@ -62,54 +85,153 @@ fi
 
 # Parsing LetsEncrypt account data
 source $USER_DATA/ssl/le.conf
-email=$EMAIL
-
-# Validating domain and aliases
-i=1
-for alias in $(echo $domain,$aliases |tr ',' '\n' |sort -u); do
-    $BIN/v-check-letsencrypt-domain $user $alias
-    if [ "$?" -ne 0 ]; then
-        touch $VESTA/data/queue/letsencrypt.pipe
-        sed -i "/ $domain /d" $VESTA/data/queue/letsencrypt.pipe
-        send_notice "LETSENCRYPT" "$alias validation failed"
-        check_result $E_INVALID "LE domain validation" >/dev/null
+
+# Checking wildcard alias
+if [ "$aliases" = "*.$domain" ]; then
+    wildcard='yes'
+    proto="dns-01"
+    if [ ! -e "$VESTA/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 "$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="$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
 
-    # Checking LE limits per account
-    if [ "$i" -gt 100 ]; then
-        touch $VESTA/data/queue/letsencrypt.pipe
-        sed -i "/ $domain /d" $VESTA/data/queue/letsencrypt.pipe
-        send_notice 'LETSENCRYPT' 'Limit of domains per account is reached'
-        check_result $E_LIMIT "LE can't sign more than 100 domains"
+    # 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/nginx.$domain.conf_letsencrypt"
+            sconf="$HOMEDIR/$user/conf/web/snginx.$domain.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 vvalidation 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
-    i=$((i++))
 done
 
-# Generating CSR
-ssl_dir=$($BIN/v-generate-ssl-cert "$domain" "$email" "US" "California" \
+
+# Generating new ssl certificate
+ssl_dir=$($BIN/v-generate-ssl-cert "$domain" "info@$domain" "US" "California"\
     "San Francisco" "Vesta" "IT" "$aliases" |tail -n1 |awk '{print $2}')
 
-# Signing CSR
-crt=$($BIN/v-sign-letsencrypt-csr $user $domain $ssl_dir)
-if [ "$?" -ne 0 ]; then
-    touch $VESTA/data/queue/letsencrypt.pipe
-    sed -i "/ $domain /d" $VESTA/data/queue/letsencrypt.pipe
-    send_notice "LETSENCRYPT" "$alias validation failed"
-    check_result "$E_INVALID" "LE $domain validation"
-fi
-echo "$crt" > $ssl_dir/$domain.crt
-
-# Dowloading CA certificate
-le_certs='https://letsencrypt.org/certs'
-x1='lets-encrypt-x1-cross-signed.pem.txt'
-x3='lets-encrypt-x3-cross-signed.pem.txt'
-issuer=$(openssl x509 -text -in $ssl_dir/$domain.crt |grep "Issuer:")
-if [ -z "$(echo $issuer|grep X3)" ]; then
-    curl -s $le_certs/$x1 > $ssl_dir/$domain.ca
-else
-    curl -s $le_certs/$x3 > $ssl_dir/$domain.ca
+# Sedning 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
+
 # Adding SSL
 ssl_home=$(search_objects 'web' 'LETSENCRYPT' 'yes' 'SSL_HOME')
 $BIN/v-delete-web-domain-ssl $user $domain >/dev/null 2>&1
@@ -140,18 +262,13 @@ update_object_value 'web' 'DOMAIN' "$domain" '$LETSENCRYPT' 'yes'
 #                       Vesta                              #
 #----------------------------------------------------------#
 
-# Restarting web
-$BIN/v-restart-web $restart
-if [ "$?" -ne 0  ]; then
-    send_notice 'LETSENCRYPT' "web server needs to be restarted manually"
-fi
+# Deleteing task from queue
+touch $VESTA/data/queue/letsencrypt.pipe
+sed -i "/ $domain /d" $VESTA/data/queue/letsencrypt.pipe
 
 # Notifying user
 send_notice 'LETSENCRYPT' "$domain SSL has been installed successfully"
 
-# Deleteing task from queue
-touch $VESTA/data/queue/letsencrypt.pipe
-sed -i "/ $domain /d" $VESTA/data/queue/letsencrypt.pipe
 
 # Logging
 log_event "$OK" "$ARGUMENTS"

+ 61 - 102
bin/v-add-letsencrypt-user

@@ -1,8 +1,8 @@
 #!/bin/bash
 # info: register letsencrypt user account
-# options: USER [TYPE]
+# options: USER
 #
-# The function creates and register LetsEncript account key
+# The function creates and register LetsEncript account 
 
 
 #----------------------------------------------------------#
@@ -11,8 +11,9 @@
 
 # Argument definition
 user=$1
-type=${2-1}
-key_size=4096
+
+# LE API
+API='https://acme-v02.api.letsencrypt.org'
 
 # Includes
 source $VESTA/func/main.sh
@@ -23,22 +24,39 @@ 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", "jwk": '$jwk'}'
+    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 '1' "$#" 'USER [TYPE]'
+check_args '1' "$#" 'USER'
 is_format_valid 'user'
 is_object_valid 'user' 'USER' "$user"
 if [ -e "$USER_DATA/ssl/le.conf" ]; then
     source "$USER_DATA/ssl/le.conf"
-    if [ "$type" -eq 1 ] && [ ! -z "$EMAIL" ]; then
-        exit
-    fi
-    if [ "$type" -eq 2 ] && [ ! -z "$KID" ]; then
-        exit
-    fi
+fi
+if [ ! -z "$KID" ]; then
+    exit
 fi
 
 
@@ -46,108 +64,57 @@ fi
 #                       Action                             #
 #----------------------------------------------------------#
 
-# Defining LE API endpoint
-if [ "$type" -eq 1 ]; then
-    api='https://acme-v01.api.letsencrypt.org'
-else
-    api='https://acme-v02.api.letsencrypt.org'
-fi
 
 # Defining user email
-if [ $type -eq 1 ]; then
-    email=$(get_user_value '$CONTACT')
+if [[ -z "$EMAIL" ]]; then
+    EMAIL=$(get_user_value '$CONTACT')
 fi
 
 # Defining user agreement
-if [ "$type" -eq 1 ]; then
-    agreement=$(curl -s -I "$api/terms" |grep Location |\
-        cut -f 2 -d \ |tr -d '\r\n')
-else
-    #agreement=$(curl -s "$api/directory" |grep termsOfService |\
-    #    cut -f 4 -d '"')
-    agreement=''
-fi
+agreement=''
 
 # Generating user key
-key="$USER_DATA/ssl/user.key"
-if [ ! -e "$key" ]; then
-    openssl genrsa -out $key $key_size >/dev/null 2>&1
-    chmod 600 $key
+KEY="$USER_DATA/ssl/user.key"
+if [ ! -e "$KEY" ]; then
+    openssl genrsa -out $KEY 4096 >/dev/null 2>&1
+    chmod 600 $KEY
 fi
 
 # Defining key exponent
 if [ -z "$EXPONENT" ]; then
-    exponent=$(openssl pkey -inform pem -in "$key" -noout -text_pub |\
+    EXPONENT=$(openssl pkey -inform pem -in "$KEY" -noout -text_pub |\
         grep Exponent: |cut -f 2 -d '(' |cut -f 1 -d ')' |sed -e 's/x//' |\
         xxd -r -p |encode_base64)
-else
-    exponent="$EXPONENT"
 fi
 
 # Defining key modulus
 if [ -z "$MODULUS" ]; then
-    modulus=$(openssl rsa -in "$key" -modulus -noout |\
+    MODULUS=$(openssl rsa -in "$KEY" -modulus -noout |\
         sed -e 's/^Modulus=//' |xxd -r -p |encode_base64)
-else
-    modulus="$MODULUS"
 fi
 
-# Defining JWK token
-jwk='{"e":"'$exponent'","kty":"RSA","n":"'"$modulus"'"}'
+# Defining JWK
+jwk='{"e":"'$EXPONENT'","kty":"RSA","n":"'"$MODULUS"'"}'
 
 # Defining key thumbnail
 if [ -z "$THUMB" ]; then
-    thumb="$(echo -n "$jwk" |openssl dgst -sha256 -binary |encode_base64)"
-else
-    thumb="$THUMB"
-fi
-
-# Requesting ACME nonce
-nonce=$(curl -s -I "$api/directory" |grep Nonce |cut -f 2 -d \ |tr -d '\r\n')
-
-# Defining payload and protected data for v1 and v2
-if [ "$type" -eq 1 ]; then
-    header='{"alg":"RS256","jwk":'"$jwk"'}'
-    protected='{"nonce":"'"$nonce"'"}'
-    payload='{"resource":"new-reg","contact":["mailto:'"$email"'"],'
-    payload=$payload'"agreement":"'$agreement'"}'
-
-else
-    protected='{"nonce": "'$nonce'",'
-    protected=''$protected' "url": "'$api/acme/new-acct'",'
-    protected=''$protected' "alg": "RS256", "jwk": '$jwk'}'
-    payload='{"termsOfServiceAgreed": true}'
+    THUMB="$(echo -n "$jwk" |openssl dgst -sha256 -binary |encode_base64)"
 fi
 
-# Encoding data
-protected=$(echo -n "$protected" |encode_base64)
-payload=$(echo -n "$payload" |encode_base64)
-
-# Signing request
-signature=$(printf "%s" "$protected.$payload" |\
-    openssl dgst -sha256 -binary -sign "$key" |\
-    encode_base64)
 
-if [ "$type" -eq 1 ]; then
-    data='{"header":'"$header"',"protected":"'"$protected"'",'
-    data=$data'"payload":"'"$payload"'","signature":"'"$signature"'"}'
-
-    answer=$(curl -s -i -d "$data" "$api/acme/new-reg")
-    status=$(echo "$answer" |grep HTTP/1.1 |tail -n1 |cut -f2 -d ' ')
-else
-    data='{"protected":"'"$protected"'",'
-    data=$data'"payload":"'"$payload"'",'
-    data=$data'"signature":"'"$signature"'"}'
-
-    answer=$(curl -s -i -d "$data" "$api/acme/new-acct" \
-        -H "Content-Type: application/jose+json")
-    status=$(echo "$answer" |grep HTTP/1.1 |tail -n1 |cut -f2 -d ' ')
-    kid=$(echo "$answer" |grep Location: |cut -f2 -d ' '|tr -d '\r')
-fi
-
-# Checking http answer status
-if [[ "${status:0:2}" -ne "20" ]] && [[ "$status" -ne "409" ]]; then
-    check_result $E_CONNECT "LetsEncrypt account registration $status"
+# Requesting ACME nonce
+nonce=$(curl -s -I "$API/directory" |grep Nonce |cut -f 2 -d \ |tr -d '\r\n')
+
+# Creating ACME account
+url="$API/acme/new-acct"
+payload='{"termsOfServiceAgreed": true}'
+answer=$(query_le_v2 "$url" "$payload" "$nonce")
+kid=$(echo "$answer" |grep Location: |cut -f2 -d ' '|tr -d '\r')
+
+# Checking answer status
+status=$(echo "$answer" |grep HTTP/1.1 |tail -n1 |cut -f2 -d ' ')
+if [[ "${status:0:2}" -ne "20" ]]; then
+    check_result $E_CONNECT "Let's Encrypt acc registration failed $status"
 fi
 
 
@@ -157,23 +124,15 @@ fi
 
 # Adding le.conf
 if [ ! -e "$USER_DATA/ssl/le.conf" ]; then
-    echo "EXPONENT='$exponent'" > $USER_DATA/ssl/le.conf
-    echo "MODULUS='$modulus'" >> $USER_DATA/ssl/le.conf
-    echo "THUMB='$thumb'" >> $USER_DATA/ssl/le.conf
-    if [ "$type" -eq 1 ]; then
-        echo "EMAIL='$email'" >> $USER_DATA/ssl/le.conf
-    else
-        echo "KID='$kid'" >> $USER_DATA/ssl/le.conf
-    fi
+    echo "EXPONENT='$EXPONENT'" > $USER_DATA/ssl/le.conf
+    echo "MODULUS='$MODULUS'" >> $USER_DATA/ssl/le.conf
+    echo "THUMB='$THUMB'" >> $USER_DATA/ssl/le.conf
+    echo "EMAIL='$EMAIL'" >> $USER_DATA/ssl/le.conf
+    echo "KID='$kid'" >> $USER_DATA/ssl/le.conf
     chmod 660  $USER_DATA/ssl/le.conf
 else
-    if [ "$type" -eq 1 ]; then
-        sed -i '/^EMAIL=/d' $USER_DATA/ssl/le.conf
-        echo "EMAIL='$email'" >> $USER_DATA/ssl/le.conf
-    else
-        sed -i '/^KID=/d' $USER_DATA/ssl/le.conf
-        echo "KID='$kid'" >> $USER_DATA/ssl/le.conf
-    fi
+    sed -i '/^KID=/d' $USER_DATA/ssl/le.conf
+    echo "KID='$kid'" >> $USER_DATA/ssl/le.conf
 fi
 
 # Logging

+ 0 - 162
bin/v-check-letsencrypt-domain

@@ -1,162 +0,0 @@
-#!/bin/bash
-# info: check letsencrypt domain
-# options: USER DOMAIN
-#
-# The function check and validates domain with LetsEncript
-
-
-#----------------------------------------------------------#
-#                    Variable&Function                     #
-#----------------------------------------------------------#
-
-# Argument definition
-user=$1
-domain=$2
-
-# Includes
-source $VESTA/func/main.sh
-source $VESTA/conf/vesta.conf
-
-# encode base64
-encode_base64() {
-    cat |base64 |tr '+/' '-_' |tr -d '\r\n='
-}
-
-# Additional argument formatting
-format_domain_idn
-
-
-#----------------------------------------------------------#
-#                    Verifications                         #
-#----------------------------------------------------------#
-
-check_args '2' "$#" 'USER DOMAIN'
-is_format_valid 'user' 'domain'
-is_system_enabled "$WEB_SYSTEM" 'WEB_SYSTEM'
-is_object_valid 'user' 'USER' "$user"
-is_object_unsuspended 'user' 'USER' "$user"
-if [ ! -e "$USER_DATA/ssl/le.conf" ]; then
-    check_result $E_NOTEXIST "LetsEncrypt key doesn't exist"
-fi
-rdomain=$(egrep "'$domain'|'$domain,|,$domain,|,$domain'" $USER_DATA/web.conf)
-if [ -z "$rdomain" ]; then
-    check_result $E_NOTEXIST "domain $domain doesn't exist"
-fi
-
-
-#----------------------------------------------------------#
-#                       Action                             #
-#----------------------------------------------------------#
-
-source $USER_DATA/ssl/le.conf
-api='https://acme-v01.api.letsencrypt.org'
-r_domain=$(echo "$rdomain" |cut -f 2 -d \')
-key="$USER_DATA/ssl/user.key"
-exponent="$EXPONENT"
-modulus="$MODULUS"
-thumb="$THUMB"
-
-# Defining JWK header
-header='{"e":"'$exponent'","kty":"RSA","n":"'"$modulus"'"}'
-header='{"alg":"RS256","jwk":'"$header"'}'
-
-# Requesting nonce
-nonce=$(curl -s -I "$api/directory" |grep Nonce |cut -f2 -d \ |tr -d '\r\n')
-protected=$(echo -n '{"nonce":"'"$nonce"'"}' |encode_base64)
-
-# Defining ACME query (request challenge)
-query='{"resource":"new-authz","identifier"'
-query=$query':{"type":"dns","value":"'"$domain_idn"'"}}'
-payload=$(echo -n "$query" |encode_base64)
-signature=$(printf "%s" "$protected.$payload" |\
-    openssl dgst -sha256 -binary -sign "$key" |encode_base64)
-data='{"header":'"$header"',"protected":"'"$protected"'",'
-data=$data'"payload":"'"$payload"'","signature":"'"$signature"'"}'
-
-# Sending request to LetsEncrypt API
-answer=$(curl -s -i -d "$data" "$api/acme/new-authz")
-
-# Checking http answer status
-status=$(echo "$answer" |grep HTTP/1.1 |tail -n1 |cut -f2 -d ' ')
-if [[ "$status" -ne "201" ]]; then
-    check_result $E_CONNECT "LetsEncrypt challenge request $status"
-fi
-
-# Parsing domain nonce,token and uri
-nonce=$(echo "$answer" |grep Nonce |cut -f2 -d \ |tr -d '\r\n')
-protected=$(echo -n '{"nonce":"'"$nonce"'"}' |encode_base64)
-token=$(echo "$answer" |grep -A 3 http-01 |grep token |cut -f 4 -d \")
-uri=$(echo "$answer" |grep -A 3 http-01 |grep uri |cut -f 4 -d \")
-
-# Adding location wrapper for request challenge
-if [ "$WEB_SYSTEM" = 'nginx' ] || [ "$PROXY_SYSTEM" = 'nginx' ]; then
-    conf="$HOMEDIR/$user/conf/web/nginx.$r_domain.conf_letsencrypt"
-    sconf="$HOMEDIR/$user/conf/web/snginx.$r_domain.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
-else
-    acme="$HOMEDIR/$user/web/$r_domain/public_html/.well-known/acme-challenge"
-    if [ ! -d "$acme" ]; then
-        mkdir -p $acme
-    fi
-    echo "$token.$thumb" > $acme/$token
-    chown -R $user:$user $HOMEDIR/$user/web/$r_domain/public_html/.well-known
-fi
-
-# Restarting web server
-if [ -z "$PROXY_SYSTEM" ]; then
-    $BIN/v-restart-web
-    check_result $? "Proxy restart failed" >/dev/null
-else
-    $BIN/v-restart-proxy
-    $BIN/v-restart-web
-    check_result $? "Web restart failed" >/dev/null
-fi
-
-# Defining ACME query (request validation)
-query='{"resource":"challenge","type":"http-01","keyAuthorization"'
-query=$query':"'$token.$thumb'","token":"'$token'"}'
-payload=$(echo -n "$query" |encode_base64)
-signature=$(printf "%s" "$protected.$payload" |\
-    openssl dgst -sha256 -binary -sign "$key" |encode_base64)
-data='{"header":'"$header"',"protected":"'"$protected"'",'
-data=$data'"payload":"'"$payload"'","signature":"'"$signature"'"}'
-
-# Sending request to LetsEncrypt API
-answer=$(curl -s -i -d "$data" "$uri")
-
-# Checking domain validation status
-i=1
-status=$(echo $answer |tr ',' '\n' |grep status |cut -f 4 -d \")
-location=$(echo "$answer" |grep Location: |awk '{print $2}' |tr -d '\r\n')
-while [ "$status" = 'pending' ]; do
-    answer=$(curl -s -i "$location")
-    detail="$(echo $answer |tr ',' '\n' |grep detail |cut -f 4 -d \")"
-    status=$(echo "$answer" |tr ',' '\n' |grep status |cut -f 4 -d \")
-    sleep 1
-    i=$((i + 1))
-    if [ "$i" -gt 60 ]; then
-        check_result $E_CONNECT "$detail"
-    fi
-done
-if [ "$status" = 'invalid' ]; then
-    detail="$(echo $answer |tr ',' '\n' |grep detail |cut -f 4 -d \")"
-    check_result $E_CONNECT "$detail"
-fi
-
-
-#----------------------------------------------------------#
-#                       Vesta                              #
-#----------------------------------------------------------#
-
-# Logging
-log_event "$OK" "$ARGUMENTS"
-
-exit

+ 0 - 110
bin/v-sign-letsencrypt-csr

@@ -1,110 +0,0 @@
-#!/bin/bash
-# info: sing letsencrypt csr
-# options: USER DOMAIN CSR_DIR [FORMAT]
-#
-# The function signs certificate request using LetsEncript API
-
-
-#----------------------------------------------------------#
-#                    Variable&Function                     #
-#----------------------------------------------------------#
-
-# Argument definition
-user=$1
-domain=$2
-csr="$3/$domain.csr"
-format=$4
-
-# Includes
-source $VESTA/func/main.sh
-source $VESTA/conf/vesta.conf
-
-# encode base64
-encode_base64() {
-    cat |base64 |tr '+/' '-_' |tr -d '\r\n='
-}
-
-
-#----------------------------------------------------------#
-#                    Verifications                         #
-#----------------------------------------------------------#
-
-check_args '3' "$#" 'USER DOMAIN CSR'
-is_format_valid 'user' 'domain'
-is_system_enabled "$WEB_SYSTEM" 'WEB_SYSTEM'
-is_object_valid 'user' 'USER' "$user"
-is_object_unsuspended 'user' 'USER' "$user"
-if [ ! -e "$USER_DATA/ssl/le.conf" ]; then
-    check_result $E_NOTEXIST "LetsEncrypt key doesn't exist"
-fi
-check_domain=$(grep -w "$domain'" $USER_DATA/web.conf)
-if [ -z "$check_domain" ]; then
-    check_result $E_NOTEXIST "domain $domain doesn't exist"
-fi
-if [ ! -e "$csr" ]; then
-    check_result $E_NOTEXIST "$csr doesn't exist"
-fi
-
-
-#----------------------------------------------------------#
-#                       Action                             #
-#----------------------------------------------------------#
-
-source $USER_DATA/ssl/le.conf
-api='https://acme-v01.api.letsencrypt.org'
-key="$USER_DATA/ssl/user.key"
-exponent="$EXPONENT"
-modulus="$MODULUS"
-thumb="$THUMB"
-
-# Defining JWK header
-header='{"e":"'$exponent'","kty":"RSA","n":"'"$modulus"'"}'
-header='{"alg":"RS256","jwk":'"$header"'}'
-
-# Requesting nonce
-nonce=$(curl -s -I "$api/directory" |grep Nonce |cut -f2 -d \ |tr -d '\r\n')
-protected=$(echo -n '{"nonce":"'"$nonce"'"}' |encode_base64)
-
-# Defining ACME query (request challenge)
-csr=$(openssl req -in $csr -outform DER |encode_base64)
-query='{"resource":"new-cert","csr":"'$csr'"}'
-payload=$(echo -n "$query" |encode_base64)
-signature=$(printf "%s" "$protected.$payload" |\
-    openssl dgst -sha256 -binary -sign "$key" |encode_base64)
-data='{"header":'"$header"',"protected":"'"$protected"'",'
-data=$data'"payload":"'"$payload"'","signature":"'"$signature"'"}'
-
-# Sending request to LetsEncrypt API
-answer=$(mktemp)
-curl -s -d "$data" "$api/acme/new-cert" -o $answer
-if [ ! -z "$(grep Error $answer)" ]; then
-    detail="$(cat $answer |tr ',' '\n' |grep detail |cut -f 4 -d \")"
-    detail=$(echo "$detail" |awk -F "::" '{print $2}')
-    rm $answer
-    check_result $E_LIMIT "$detail"
-fi
-
-# Printing certificate
-crt=$(cat "$answer" |openssl base64 -e)
-rm $answer
-if [ "$format" != 'json' ]; then
-    echo "-----BEGIN CERTIFICATE-----"
-    echo "$crt"
-    echo "-----END CERTIFICATE-----"
-else
-    echo -e "{\n\t\"$domain\": {\n\t\t\"CRT\":\""
-    echo -n '-----BEGIN CERTIFICATE-----\n'
-    echo -n "$crt" |sed ':a;N;$!ba;s/\n/\\n/g'
-    echo -n '-----END CERTIFICATE-----'
-    echo -e  "\"\n\t\t}\n\t}"
-fi
-
-
-#----------------------------------------------------------#
-#                       Vesta                              #
-#----------------------------------------------------------#
-
-# Logging
-log_event "$OK" "$ARGUMENTS"
-
-exit

+ 18 - 37
bin/v-update-letsencrypt-ssl

@@ -22,51 +22,32 @@ source $VESTA/conf/vesta.conf
 #                       Action                             #
 #----------------------------------------------------------#
 
-# Defining user list
-users=$($BIN/v-list-users | tail -n+3 | awk '{ print $1 }')
-
-lecounter=0
-
-# Checking users
-for user in $users; do
+# Checking user certificates
+for user in $($BIN/v-list-users plain |cut -f 1); do
     USER_DATA=$VESTA/data/users/$user
-    # Checking user certificates
+    lecounter=0
+
     for domain in $(search_objects 'web' 'LETSENCRYPT' 'yes' 'DOMAIN'); do
-        # Working on Web domain check - if is suspended
-        webSuspended=$(grep "DOMAIN='$domain'" $USER_DATA/web.conf |grep "SUSPENDED='yes")
-        if [ ! -z "$webSuspended" ]; then
-                continue;
-        fi;
-        crt="$VESTA/data/users/$user/ssl/$domain.crt"
-        crt_data=$(openssl x509 -text -in "$crt")
-        expire=$(echo "$crt_data" |grep "Not After")
-        expire=$(echo "$expire" |cut -f 2,3,4 -d :)
-        expire=$(date -d "$expire" +%s)
+        crt_data=$(openssl x509 -text -in $USER_DATA/ssl/$domain.crt)
+        not_after=$(echo "$crt_data" |grep "Not After" |cut -f 2,3,4 -d :)
+        expiration=$(date -d "$not_after" +%s)
         now=$(date +%s)
-        expire=$((expire - now))
-        expire=$((expire / 86400))
-        domain=$(basename $crt |sed -e "s/.crt$//")
-        if [[ "$expire" -lt 31 ]]; then
-            if [ $lecounter -gt 0 ]; then
-                sleep 10
-            fi
-            ((lecounter++))
+        seconds_valid=$((expiration - now))
+        days_valid=$((seconds_valid / 86400))
+        if [[ "$days_valid" -lt 31 ]]; then
             aliases=$(echo "$crt_data" |grep DNS:)
             aliases=$(echo "$aliases" |sed -e "s/DNS://g" -e "s/,//")
             aliases=$(echo "$aliases" |tr ' ' '\n' |sed "/^$/d")
             aliases=$(echo "$aliases" |grep -v "^$domain$")
-            if [ ! -z "$aliases" ]; then
-                aliases=$(echo "$aliases" |sed -e ':a;N;$!ba;s/\n/,/g')
-                msg=$($BIN/v-add-letsencrypt-domain $user $domain $aliases)
-                if [ $? -ne 0 ]; then
-                    echo "$domain $msg"
-                fi
-            else
-                msg==$($BIN/v-add-letsencrypt-domain $user $domain)
-                if [ $? -ne 0 ]; then
-                    echo "$domain $msg"
-                fi
+            aliases=$(echo "$aliases" |sed -e ':a;N;$!ba;s/\n/,/g')
+            msg=$($BIN/v-add-letsencrypt-domain $user $domain $aliases)
+            if [ $? -ne 0 ]; then
+                echo "$domain $msg"
             fi
+            if [ $lecounter -gt 0 ]; then
+                sleep 10
+            fi
+            ((lecounter++))
         fi
     done
 done