#!/bin/bash # info: register letsencrypt user account # options: USER # # example: v-add-letsencrypt-user bob # # This function creates and register LetsEncrypt account #----------------------------------------------------------# # Variables & Functions # #----------------------------------------------------------# # Argument definition user=$1 # Includes # shellcheck source=/etc/hestiacp/hestia.conf source /etc/hestiacp/hestia.conf # shellcheck source=/usr/local/hestia/func/main.sh source $HESTIA/func/main.sh # load config file source_conf "$HESTIA/conf/hestia.conf" # LE API LE_API='https://acme-v02.api.letsencrypt.org' if [[ "$LE_STAGING" = 'yes' ]]; then LE_API='https://acme-staging-v02.api.letsencrypt.org' fi # 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", "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 --user-agent "HestiaCP" -s -i -d "$post_data" "$1" -H "$content" } #----------------------------------------------------------# # Verifications # #----------------------------------------------------------# 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" fi if [ -n "$KID" ]; then exit fi # Perform verification if read-only mode is enabled check_hestia_demo_mode #----------------------------------------------------------# # Action # #----------------------------------------------------------# # Defining user email if [[ -z "$EMAIL" ]]; then EMAIL=$(get_user_value '$CONTACT') fi # Defining user agreement agreement='' # Generating user 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 \ | grep Exponent: | cut -f 2 -d '(' | cut -f 1 -d ')' | sed -e 's/x//' \ | xxd -r -p | encode_base64) fi # Defining key modulus if [ -z "$MODULUS" ]; then MODULUS=$(openssl rsa -in "$KEY" -modulus -noout \ | sed -e 's/^Modulus=//' | xxd -r -p | encode_base64) fi # 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)" fi # Requesting ACME nonce nonce=$(curl -s -I "$LE_API/directory" | grep -i nonce | cut -f2 -d\ | tr -d '\r\n') # Creating ACME account url="$LE_API/acme/new-acct" payload='{"termsOfServiceAgreed": true}' answer=$(query_le_v2 "$url" "$payload" "$nonce") kid=$(echo "$answer" | grep -i location: | cut -f2 -d ' ' | tr -d '\r') # Checking answer status status=$(echo "$answer" | grep HTTP/ | tail -n1 | cut -f2 -d ' ') if [[ "${status:0:2}" -ne "20" ]]; then check_result "$E_CONNECT" "Let's Encrypt acc registration failed $status" fi #----------------------------------------------------------# # Hestia # #----------------------------------------------------------# # 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 echo "EMAIL='$EMAIL'" >> $USER_DATA/ssl/le.conf echo "KID='$kid'" >> $USER_DATA/ssl/le.conf chmod 660 $USER_DATA/ssl/le.conf else sed -i '/^KID=/d' $USER_DATA/ssl/le.conf echo "KID='$kid'" >> $USER_DATA/ssl/le.conf fi # Logging log_event "$OK" "$ARGUMENTS" exit