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
1818source /etc/hestiacp/hestia.conf
1919# load config file
2020source_conf " $HESTIA /conf/hestia.conf"
2121
22- # Check required binaries
2322if [ ! -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
3433fi
35-
3634# Put this to 0 if you want use bash -x to debug it
3735debug=1
3836hestia_package=default
37+ letsencrypt_enable=0
38+ addusertext=" IMPORTED"
3939tmp_dir=' tmp_dir_da_backup'
4040time=$( echo " $time_n_date " | cut -f 1 -d \ )
4141date=$( 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+
5965tput setaf 3
6066echo " #######################################"
6167echo " # START WITH IMPORT "
@@ -138,13 +144,13 @@ else
138144 exit 3
139145fi
140146
141- cd /backup/${tmp_dir} /
147+ cd /backup/${tmp_dir} / || exit
142148main_dir=$( pwd)
143149echo " Access tmp directory $main_dir "
144150directadmin_user=$( grep username backup/user.conf | cut -d " =" -f 2)
145151directadmin_usermail=$( grep email backup/user.conf | cut -d " =" -f 2 | grep @)
146152echo " 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)
149155fi
150156
156162
157163echo " Generate random password for $directadmin_user and create Hestiacp Account ..."
158164new_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
160166if [ " $? " -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"
300317tput sgr0
301318function 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}
309326echo cat restored_domains
310327if [ -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
337354fi
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+
338458delete_tmp
339459tput sgr0
340460tput setaf 2
0 commit comments