forked from hestiacp/hestiacp
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathv-add-letsencrypt-domain
More file actions
executable file
·307 lines (262 loc) · 10.6 KB
/
v-add-letsencrypt-domain
File metadata and controls
executable file
·307 lines (262 loc) · 10.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
#!/bin/bash
# info: check letsencrypt domain
# options: USER DOMAIN [ALIASES] [MAIL]
#
# The function check and validates domain with Let's Encrypt
#----------------------------------------------------------#
# Variable&Function #
#----------------------------------------------------------#
# Argument definition
user=$1
domain=$2
aliases=$3
mail=$3
# 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] [MAIL]'
is_format_valid 'user' 'domain' 'aliases'
is_object_valid 'user' 'USER' "$user"
is_object_unsuspended 'user' 'USER' "$user"
if [ -z "$mail" ]; then
is_system_enabled "$WEB_SYSTEM" 'WEB_SYSTEM'
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
else
is_system_enabled "$MAIL_SYSTEM" 'MAIL_SYSTEM'
is_object_valid 'mail' 'DOMAIN' "$domain"
is_object_unsuspended 'mail' 'DOMAIN' "$domain"
is_object_value_empty 'mail' 'DOMAIN' "$domain" '$SSL'
fi
#----------------------------------------------------------#
# Action #
#----------------------------------------------------------#
# Rework domain and alieses for mail.
if [ ! -z "$mail" ]; then
original_domain=$domain
aliases="webmail.$domain,autodiscover.$domain"
domain="mail.$domain"
fi
# 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/$PROXY_SYSTEM.conf_letsencrypt"
sconf="$HOMEDIR/$user/conf/web/$domain/$PROXY_SYSTEM.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
if [ -z "$mail" ]; then
ssl_home=$(search_objects 'web' 'LETSENCRYPT' 'yes' 'SSL_HOME')
$BIN/v-delete-web-domain-ssl $user $domain > /dev/null 2>&1
$BIN/v-add-web-domain-ssl $user $domain $ssl_dir $ssl_home
else
$BIN/v-delete-mail-domain-ssl $user $domain >/dev/null 2>&1
$BIN/v-add-mail-domain-ssl $user $domain $ssl_dir
fi
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 "$mail" ]; then
if [ -z "$LETSENCRYPT" ]; then
add_object_key "web" 'DOMAIN' "$domain" 'LETSENCRYPT' 'FTP_USER'
fi
update_object_value 'web' 'DOMAIN' "$domain" '$LETSENCRYPT' 'yes'
else
if [ -z "$LETSENCRYPT" ]; then
add_object_key "mail" 'DOMAIN' "$original_domain" 'LETSENCRYPT'
fi
update_object_value 'mail' 'DOMAIN' "$original_domain" '$LETSENCRYPT' 'yes'
fi
#----------------------------------------------------------#
# 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