Skip to content

Commit 869f8b6

Browse files
authored
Merge pull request hestiacp#4426 from ricardo777/patch-6
Extend DirectAdmin import
2 parents f2dd183 + f6aefd0 commit 869f8b6

File tree

1 file changed

+165
-45
lines changed

1 file changed

+165
-45
lines changed

bin/v-import-directadmin

Lines changed: 165 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,18 @@
77
# Credits: Maks Usmanov (skamasle), Jaap Marcus (jaapmarcus) and contributors:
88
# Thanks to <https://github.com/Skamasle/sk_da_importer/graphs/contributors>
99

10-
# This script is provided whitout any warranty
10+
# This script is provided without any warranty
1111
# Run at your own risk
1212
# Version 0.1
1313
# This script restore backups from DA to Hestiacp
1414

1515
# shellcheck source=/usr/local/hestia/func/main.sh
16-
source $HESTIA/func/main.sh
16+
source "$HESTIA"/func/main.sh
1717
# shellcheck source=/etc/hestiacp/hestia.conf
1818
source /etc/hestiacp/hestia.conf
1919
# load config file
2020
source_conf "$HESTIA/conf/hestia.conf"
2121

22-
# Check required binaries
2322
if [ ! -e /usr/bin/rsync ] || [ ! -e /usr/bin/file ]; then
2423
echo "#######################################"
2524
echo "rsync not installed, try install it"
@@ -32,10 +31,11 @@ if [ ! -e /usr/bin/rsync ] || [ ! -e /usr/bin/file ]; then
3231
fi
3332
exit 3
3433
fi
35-
3634
# Put this to 0 if you want use bash -x to debug it
3735
debug=1
3836
hestia_package=default
37+
letsencrypt_enable=0
38+
addusertext="IMPORTED"
3939
tmp_dir='tmp_dir_da_backup'
4040
time=$(echo "$time_n_date" | cut -f 1 -d \ )
4141
date=$(echo "$time_n_date" | cut -f 2 -d \ )
@@ -56,6 +56,12 @@ delete_tmp() {
5656
rm -rf /backup/${tmp_dir}
5757
}
5858

59+
# URL decoding function
60+
urldecode() {
61+
local url_encoded="${1//+/ }"
62+
printf '%b' "${url_encoded//%/\\x}"
63+
}
64+
5965
tput setaf 3
6066
echo "#######################################"
6167
echo "# START WITH IMPORT "
@@ -138,13 +144,13 @@ else
138144
exit 3
139145
fi
140146

141-
cd /backup/${tmp_dir}/
147+
cd /backup/${tmp_dir}/ || exit
142148
main_dir=$(pwd)
143149
echo "Access tmp directory $main_dir"
144150
directadmin_user=$(grep username backup/user.conf | cut -d "=" -f 2)
145151
directadmin_usermail=$(grep email backup/user.conf | cut -d "=" -f 2 | grep @)
146152
echo "Get User: $directadmin_user"
147-
if [ -z $directadmin_usermail ]; then
153+
if [ -z "$directadmin_usermail" ]; then
148154
directadmin_usermail=$(grep domain backup/user.conf | cut -d "=" -f 2 | head -n 1)
149155
fi
150156

@@ -156,7 +162,7 @@ fi
156162

157163
echo "Generate random password for $directadmin_user and create Hestiacp Account ..."
158164
new_password=$(generate_password)
159-
$BIN/v-add-user $directadmin_user $new_password $directadmin_usermail $hestia_package
165+
"$BIN"/v-add-user "$directadmin_user" "$new_password" "$directadmin_usermail" $hestia_package $addusertext
160166
if [ "$?" -ne 0 ]; then
161167
tput setaf 1
162168
echo "Error: Unable to create user"
@@ -184,45 +190,56 @@ function run_da_db() {
184190
for da_db in $da_db_list; do
185191

186192
database_name=${da_db::-5}
187-
grep -w $database_name server_dbs
193+
grep -w "$database_name" server_dbs
188194
if [ $? == "1" ]; then
189195
if [ -e "backup/${database_name}.sql" ]; then
190196

191-
#Get the database name
192-
db=$(grep db_collation backup/${da_db} | tr '&' '\n ' | grep SCHEMA_NAME | cut -d "=" -f 2)
197+
# Get the database name
198+
db=$(grep db_collation backup/"${da_db}" | tr '&' '\n ' | grep SCHEMA_NAME | cut -d "=" -f 2)
193199

194200
tput setaf 2
195201
echo " Create and restore ${db} "
196202
tput sgr0
197203
mysql -e "CREATE DATABASE $db"
198-
mysql ${db} < backup/${db}.sql
199-
#Get all the users of the database
200-
while IFS= read -r line; do
201204

202-
selectdb_line=$(echo $line | grep passwd)
203-
if [ ! -z "$selectdb_line" ]; then
205+
# Preprocess the SQL file to remove problematic lines: https://jira.mariadb.org/browse/MDEV-34203
206+
grep -vE '^/\*!(999999\\-)' "backup/${database_name}.sql" > "backup/${database_name}_processed.sql" 2> /dev/null
207+
208+
# Import the preprocessed SQL file with --force to ignore errors and continue
209+
mysql --force "${db}" < "backup/${database_name}_processed.sql"
204210

205-
db_user=$(echo $selectdb_line | tr '&' '\n ' | grep ${directadmin_user} | cut -d "=" -f 1)
206-
md5=$(echo $selectdb_line | tr '&' '\n ' | grep passwd | cut -d "=" -f 2)
211+
if [ $? -ne 0 ]; then
212+
tput setaf 1
213+
echo "Error importing database $db"
214+
tput sgr0
215+
continue
216+
fi
217+
218+
# Get all the users of the database
219+
while IFS= read -r line; do
220+
selectdb_line=$(echo "$line" | grep passwd)
221+
if [ ! -z "$selectdb_line" ]; then
222+
db_user=$(echo "$selectdb_line" | tr '&' '\n ' | grep "${directadmin_user}" | cut -d "=" -f 1)
223+
encoded_md5=$(echo "$selectdb_line" | tr '&' '\n ' | grep passwd | cut -d "=" -f 2)
224+
md5=$(urldecode "$encoded_md5")
207225

208226
echo "DB: $db"
209227
echo "udb: $db_user"
210228
echo "Password: ${md5}"
211229

212-
echo "DB='$db' DBUSER='$db_user' MD5='$md5' HOST='localhost' TYPE='mysql' CHARSET='UTF8' U_DISK='0' SUSPENDED='no' TIME='$time' DATE='$data'" >> /usr/local/hestia/data/users/$directadmin_user/db.conf
230+
echo "DB='$db' DBUSER='$db_user' MD5='$md5' HOST='localhost' TYPE='mysql' CHARSET='UTF8' U_DISK='0' SUSPENDED='no' TIME='$time' DATE='$date'" >> /usr/local/hestia/data/users/"$directadmin_user"/db.conf
213231
fi
214-
215232
done < "backup/${da_db}"
216233

217-
# Leave hestia restore passwords and create users
234+
# Leave Hestia to restore passwords and create users
218235
tput setaf 2
219-
echo "Rebuild databases files for $directadmin_user"
236+
echo "Rebuild database files for $directadmin_user"
220237
tput sgr0
221-
$BIN/v-rebuild-databases $directadmin_user
238+
"$BIN"/v-rebuild-databases "$directadmin_user"
222239
fi
223240
else
224241
tput setaf 1
225-
echo "Error: Cant restore database $db alredy exists in mysql server"
242+
echo "Error: Can't restore database $db, it already exists on the MySQL server"
226243
tput sgr0
227244
fi
228245
done
@@ -250,39 +267,39 @@ for directadmin_domain in $directadmin_domain_list; do
250267
tput setaf 2
251268
echo "Add $directadmin_domain if not exists"
252269
tput sgr0
253-
$BIN/v-add-domain ${directadmin_user} $directadmin_domain
270+
"$BIN"/v-add-domain "${directadmin_user}" "$directadmin_domain"
254271
if [ $? -ne 0 ]; then
255272
tput setaf 4
256273
echo "Domain $directadmin_domain already added in some account, skip..."
257274
tput sgr0
258-
elif [ -d /home/${directadmin_user}/web/${directadmin_domain} ]; then
275+
elif [ -d /home/"${directadmin_user}"/web/"${directadmin_domain}" ]; then
259276
echo "Domain $directadmin_domain added, restoring files"
260-
echo $directadmin_domain >> restored_domains
261-
rm -f /home/$directadmin_user/web/$directadmin_domain/public_html/index.html
262-
rm -f /home/$directadmin_user/web/$directadmin_domain/public_html/robots.txt
277+
echo "$directadmin_domain" >> restored_domains
278+
rm -f /home/"$directadmin_user"/web/"$directadmin_domain"/public_html/index.html
279+
rm -f /home/"$directadmin_user"/web/"$directadmin_domain"/public_html/robots.txt
263280

264281
public_sync_count=0
265-
rsync -av domains/${directadmin_domain}/public_html/ /home/$directadmin_user/web/$directadmin_domain/public_html 2>&1 \
282+
rsync -av domains/"${directadmin_domain}"/public_html/ /home/"$directadmin_user"/web/"$directadmin_domain"/public_html 2>&1 \
266283
| while read file_dm; do
267284
public_sync_count=$(($public_sync_count + 1))
268285
echo -en "-- $public_sync_count restored files\r"
269286
done
270287

271-
chown ${directadmin_user}:${directadmin_user} -R /home/${directadmin_user}/web/${directadmin_domain}/public_html
272-
chmod 751 /home/${directadmin_user}/web/${directadmin_domain}/public_html
288+
chown "${directadmin_user}":"${directadmin_user}" -R /home/"${directadmin_user}"/web/"${directadmin_domain}"/public_html
289+
chmod 751 /home/"${directadmin_user}"/web/"${directadmin_domain}"/public_html
273290

274291
if [[ -L "domains/${directadmin_domain}/private_html" && -d "domains/${directadmin_domain}/private_html" ]]; then
275292
echo "private_html is a symlink to public_html so we don't need to copy it."
276293
else
277294
private_sync_count=0
278295

279-
rsync -av domains/${directadmin_domain}/private_html/ /home/$directadmin_user/web/$directadmin_domain/private 2>&1 \
296+
rsync -av domains/"${directadmin_domain}"/private_html/ /home/"$directadmin_user"/web/"$directadmin_domain"/private 2>&1 \
280297
| while read file_dm; do
281298
private_sync_count=$(($private_sync_count + 1))
282299
echo -en "-- $private_sync_count restored files\r"
283300
done
284-
chown ${directadmin_user}:${directadmin_user} -R /home/${directadmin_user}/web/${directadmin_domain}/private
285-
chmod 751 /home/${directadmin_user}/web/${directadmin_domain}/private
301+
chown "${directadmin_user}":"${directadmin_user}" -R /home/"${directadmin_user}"/web/"${directadmin_domain}"/private
302+
chmod 751 /home/"${directadmin_user}"/web/"${directadmin_domain}"/private
286303
fi
287304
else
288305
echo "Ups.. cant restore or add domain: $directadmin_domain"
@@ -300,41 +317,144 @@ echo "Start restoring mails"
300317
tput sgr0
301318
function da_restore_imap_pass() {
302319
#DirectAdmin passw is SHA512-CRYPT
303-
da_orig_pass=$(grep -w $1 backup/$2/email/passwd | tr ':' ' ' | cut -d " " -f2)
304-
echo ${da_orig_pass}
320+
da_orig_pass=$(grep -w "$1" backup/"$2"/email/passwd | tr ':' ' ' | cut -d " " -f2)
321+
echo "${da_orig_pass}"
305322
USER_DATA=$HESTIA/data/users/${3}/
306323
update_object_value "mail/${2}" 'ACCOUNT' "${1}" '$MD5' "{SHA512-CRYPT}$da_orig_pass"
307324
echo "Password for $1@$2 restored"
308325
}
309326
echo cat restored_domains
310327
if [ -e restored_domains ]; then
311328
cat restored_domains | while read da_mail_domain; do
312-
if [ "$(ls -A imap/${da_mail_domain}/)" ]; then
329+
if [ "$(ls -A imap/"${da_mail_domain}"/)" ]; then
313330
tput setaf 2
314331
echo "Found Imap for ${da_mail_domain}"
315332
tput sgr0
316-
ls -1 imap/${da_mail_domain}/ | while read da_imap; do
333+
ls -1 imap/"${da_mail_domain}"/ | while read da_imap; do
317334
tmp_pass=$(generate_password)
318-
$BIN/v-add-mail-account $directadmin_user $da_mail_domain $da_imap tmp_pass
335+
"$BIN"/v-add-mail-account "$directadmin_user" "$da_mail_domain" "$da_imap" "$tmp_pass"
319336
if [ "$debug" != 0 ]; then
320-
rsync -av imap/${da_mail_domain}/${da_imap}/Maildir/ /home/${directadmin_user}/mail/${da_mail_domain}/${da_imap} 2>&1 \
337+
rsync -av imap/"${da_mail_domain}"/"${da_imap}"/Maildir/ /home/"${directadmin_user}"/mail/"${da_mail_domain}"/"${da_imap}" 2>&1 \
321338
| while read backup_file_dm; do
322339
sk_sync=$((sk_sync + 1))
323340
echo -en "-- $sk_sync restored files\r"
324341
done
325342
echo " "
326343
else
327-
rsync imap/${da_mail_domain}/${da_imap}/Maildir/ /home/${directadmin_user}/mail/${da_mail_domain}/${da_imap}
344+
rsync imap/"${da_mail_domain}"/"${da_imap}"/Maildir/ /home/"${directadmin_user}"/mail/"${da_mail_domain}"/"${da_imap}"
328345
fi
329-
chown ${directadmin_user}:mail -R /home/${directadmin_user}/mail/${da_mail_domain}/${da_imap}
330-
find /home/$directadmin_user/mail/$da_mail_domain -type f -name 'dovecot*' -delete
331-
da_restore_imap_pass $da_imap $da_mail_domain $directadmin_user
346+
chown "${directadmin_user}":mail -R /home/"${directadmin_user}"/mail/"${da_mail_domain}"/"${da_imap}"
347+
find /home/"$directadmin_user"/mail/"$da_mail_domain" -type f -name 'dovecot*' -delete
348+
da_restore_imap_pass "$da_imap" "$da_mail_domain" "$directadmin_user"
332349
done
333350

334-
$BIN/v-rebuild-mail-domain $directadmin_user $da_mail_domain
351+
"$BIN"/v-rebuild-mail-domain "$directadmin_user" "$da_mail_domain"
335352
fi
336353
done
337354
fi
355+
356+
tput setaf 3
357+
echo "#######################################"
358+
echo "# CRON JOBS "
359+
echo "#######################################"
360+
tput sgr0
361+
362+
# Restore cron jobs
363+
if [ -f "backup/crontab.conf" ]; then
364+
while IFS= read -r cron_line; do
365+
# Skip empty lines and comments
366+
[[ -z "$cron_line" || "$cron_line" =~ ^#.*$ ]] && continue
367+
368+
# Check if the line is an environment variable
369+
if [[ "$cron_line" =~ ^[A-Z]+= ]]; then
370+
# Export environment variable
371+
# echo "Setting environment variable: $cron_line"
372+
export "$cron_line"
373+
continue
374+
fi
375+
376+
# Remove the cron job identifier and extract cron job details
377+
if [[ "$cron_line" =~ ^[0-9]+= ]]; then
378+
cron_line=${cron_line#*=}
379+
fi
380+
381+
# Extract cron job details (handle cases where command contains spaces)
382+
IFS=' ' read -r min hour day month wday command <<< "$cron_line"
383+
384+
# Ensure it is a valid cron job line
385+
if ! [[ "$min" =~ ^[\*0-9,-/]+$ && "$hour" =~ ^[\*0-9,-/]+$ && "$day" =~ ^[\*0-9,-/]+$ && "$month" =~ ^[\*0-9,-/]+$ && "$wday" =~ ^[\*0-9,-/]+$ ]]; then
386+
echo "Invalid cron job format: $cron_line"
387+
continue
388+
fi
389+
390+
# Reconstruct the command part
391+
command="${cron_line#"${min}" "${hour}" "${day}" "${month}" "${wday}" }"
392+
393+
echo "Adding cron job for user $directadmin_user: $cron_line"
394+
"$BIN"/v-add-cron-job "$directadmin_user" "$min" "$hour" "$day" "$month" "$wday" "$command"
395+
done < "backup/crontab.conf"
396+
else
397+
echo "No cron jobs found to restore."
398+
fi
399+
400+
tput setaf 3
401+
echo "#######################################"
402+
echo "# DOMAIN ALIASES "
403+
echo "#######################################"
404+
tput sgr0
405+
406+
# Restore domain aliases
407+
domain_base_dir="backup"
408+
409+
if [ -d "$domain_base_dir" ]; then
410+
for domain_subdir in "$domain_base_dir"/*/; do
411+
domain_pointers_file="$domain_subdir/domain.pointers"
412+
if [ -f "$domain_pointers_file" ]; then
413+
while IFS= read -r pointer_line; do
414+
# Skip empty lines and comments
415+
[[ -z "$pointer_line" || "$pointer_line" =~ ^#.*$ ]] && continue
416+
417+
# Extract alias and type
418+
alias_domain=$(echo "$pointer_line" | cut -d'=' -f1)
419+
alias_type=$(echo "$pointer_line" | awk -F'type=' '{print $2}')
420+
421+
if [[ "$alias_type" == "alias" || "$alias_type" == "pointer" ]]; then
422+
domain_name=$(basename "$domain_subdir")
423+
echo "Adding domain alias $alias_domain for user $directadmin_user on domain $domain_name"
424+
"$BIN"/v-add-web-domain-alias "$directadmin_user" "$domain_name" "$alias_domain" no
425+
else
426+
echo "Skipping non-alias type for $alias_domain: $alias_type"
427+
fi
428+
done < "$domain_pointers_file"
429+
fi
430+
done
431+
else
432+
echo "No domain directories found to restore."
433+
fi
434+
435+
tput setaf 3
436+
echo "#######################################"
437+
echo "# ENABLE LETSENCRYPT "
438+
echo "#######################################"
439+
tput sgr0
440+
441+
if [ "$letsencrypt_enable" = 1 ]; then
442+
for directadmin_domain in $directadmin_domain_list; do
443+
echo "Enabling Let's Encrypt for $directadmin_domain"
444+
letsencrypt_output=$("$BIN"/v-add-letsencrypt-domain "$directadmin_user" "$directadmin_domain" '' yes 2>&1)
445+
echo "$letsencrypt_output"
446+
if echo "$letsencrypt_output" | grep -q "Error: mail domain"; then
447+
echo "Error with Let's Encrypt: $letsencrypt_output"
448+
echo "Retrying Let's Encrypt without mail domain for $directadmin_domain"
449+
"$BIN"/v-add-letsencrypt-domain "$directadmin_user" "$directadmin_domain" '' no
450+
else
451+
echo "Let's Encrypt enabled for $directadmin_domain"
452+
fi
453+
done
454+
else
455+
echo "Let's Encrypt is not enabled for any domain."
456+
fi
457+
338458
delete_tmp
339459
tput sgr0
340460
tput setaf 2

0 commit comments

Comments
 (0)