You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							345 lines
						
					
					
						
							9.5 KiB
						
					
					
				
			
		
		
	
	
							345 lines
						
					
					
						
							9.5 KiB
						
					
					
				#!/bin/bash
 | 
						|
# info: add backup host
 | 
						|
# options: TYPE HOST USERNAME PASSWORD [PATH] [PORT]
 | 
						|
#
 | 
						|
# example: v-add-backup-host sftp backup.acme.com admin p4$$w@Rd
 | 
						|
#          v-add-backup-host b2 bucketName keyID applicationKey
 | 
						|
#
 | 
						|
# Add a new remote backup location. Currently SFTP, FTP and Backblaze are supported
 | 
						|
 | 
						|
#----------------------------------------------------------#
 | 
						|
#                Variables & Functions                     #
 | 
						|
#----------------------------------------------------------#
 | 
						|
 | 
						|
# Argument definition
 | 
						|
type=$1
 | 
						|
host=$2
 | 
						|
user=$3
 | 
						|
raw_password=$4
 | 
						|
HIDE=4
 | 
						|
password=$(perl -e 'print quotemeta shift(@ARGV)' "${raw_password}")
 | 
						|
path=${5-/backup}
 | 
						|
port=$6
 | 
						|
 | 
						|
# CPU Architecture
 | 
						|
arch=$(arch)
 | 
						|
 | 
						|
# Includes
 | 
						|
# shellcheck source=/usr/local/hestia/func/main.sh
 | 
						|
source $HESTIA/func/main.sh
 | 
						|
# load config file
 | 
						|
source_conf "$HESTIA/conf/hestia.conf"
 | 
						|
# Fetch current verison B2 CLI tool
 | 
						|
source_conf "$HESTIA/install/upgrade/upgrade.conf"
 | 
						|
 | 
						|
# Paths
 | 
						|
b2cli="/usr/local/bin/b2"
 | 
						|
b2lnk="https://github.com/Backblaze/B2_Command_Line_Tool/releases/download/v$b2_v/b2-linux"
 | 
						|
 | 
						|
# Defining ftp command function
 | 
						|
ftpc() {
 | 
						|
	ftp -p -n $host $port << EOF
 | 
						|
    quote USER $user
 | 
						|
    quote PASS $password
 | 
						|
    binary
 | 
						|
    $1
 | 
						|
    $2
 | 
						|
    $3
 | 
						|
    quit
 | 
						|
EOF
 | 
						|
}
 | 
						|
 | 
						|
# Defining sftp command function
 | 
						|
sftpc() {
 | 
						|
	if [ "$privatekey" != "yes" ]; then
 | 
						|
		expect -f "-" "$@" << EOF
 | 
						|
        set count 0
 | 
						|
        spawn /usr/bin/sftp -o StrictHostKeyChecking=no -o Port=$port $user@$host
 | 
						|
        expect {
 | 
						|
            -nocase "password:" {
 | 
						|
                send "$password\r"
 | 
						|
                exp_continue
 | 
						|
            }
 | 
						|
 | 
						|
            -re "Password for (.*)@(.*)" {
 | 
						|
                send "$password\r"
 | 
						|
                exp_continue
 | 
						|
            }
 | 
						|
 | 
						|
            -re "Couldn't|(.*)disconnect|(.*)stalled|(.*)not found" {
 | 
						|
                set count \$argc
 | 
						|
                set output "Disconnected."
 | 
						|
                set rc $E_FTP
 | 
						|
                exp_continue
 | 
						|
            }
 | 
						|
 | 
						|
            -re ".*denied.*(publickey|password)." {
 | 
						|
                set output "Permission denied, wrong publickey or password."
 | 
						|
                set rc $E_CONNECT
 | 
						|
            }
 | 
						|
 | 
						|
            "sftp>" {
 | 
						|
                if {\$count < \$argc} {
 | 
						|
                    set arg [lindex \$argv \$count]
 | 
						|
                    send "\$arg\r"
 | 
						|
                    incr count
 | 
						|
                } else {
 | 
						|
                    send "exit\r"
 | 
						|
                    set output "Disconnected."
 | 
						|
                    if {[info exists rc] != 1} {
 | 
						|
                        set rc $OK
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                exp_continue
 | 
						|
            }
 | 
						|
 | 
						|
            timeout {
 | 
						|
                set output "Connection timeout."
 | 
						|
                set rc $E_CONNECT
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        if {[info exists output] == 1} {
 | 
						|
            puts "\$output"
 | 
						|
        }
 | 
						|
 | 
						|
        exit \$rc
 | 
						|
EOF
 | 
						|
	else
 | 
						|
		expect -f "-" "$@" << EOF
 | 
						|
            set count 0
 | 
						|
            spawn /usr/bin/sftp -o StrictHostKeyChecking=no -o Port=$port -i $raw_password $user@$host
 | 
						|
            expect {
 | 
						|
 | 
						|
                -re "Couldn't|(.*)disconnect|(.*)stalled|(.*)not found" {
 | 
						|
                    set count \$argc
 | 
						|
                    set output "Disconnected."
 | 
						|
                    set rc $E_FTP
 | 
						|
                    exp_continue
 | 
						|
                }
 | 
						|
 | 
						|
                -re ".*denied.*(publickey|password)." {
 | 
						|
                    set output "Permission denied, wrong publickey or password."
 | 
						|
                    set rc $E_CONNECT
 | 
						|
                }
 | 
						|
 | 
						|
                "sftp>" {
 | 
						|
                    if {\$count < \$argc} {
 | 
						|
                        set arg [lindex \$argv \$count]
 | 
						|
                        send "\$arg\r"
 | 
						|
                        incr count
 | 
						|
                    } else {
 | 
						|
                        send "exit\r"
 | 
						|
                        set output "Disconnected."
 | 
						|
                        if {[info exists rc] != 1} {
 | 
						|
                            set rc $OK
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                    exp_continue
 | 
						|
                }
 | 
						|
 | 
						|
                timeout {
 | 
						|
                    set output "Connection timeout."
 | 
						|
                    set rc $E_CONNECT
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            if {[info exists output] == 1} {
 | 
						|
                puts "\$output"
 | 
						|
            }
 | 
						|
 | 
						|
            exit \$rc
 | 
						|
EOF
 | 
						|
	fi
 | 
						|
}
 | 
						|
 | 
						|
#----------------------------------------------------------#
 | 
						|
#                    Verifications                         #
 | 
						|
#----------------------------------------------------------#
 | 
						|
 | 
						|
if [ "$type" != 'local' ]; then
 | 
						|
	check_args '2' "$#" "TYPE HOST USERNAME PASSWORD [PATH] [PORT]"
 | 
						|
	is_format_valid 'host' 'path' 'port'
 | 
						|
	is_type_valid 'sftp,ftp,b2,rclone' "$type"
 | 
						|
	is_username_format_valid "$user" "username"
 | 
						|
	privatekey="no"
 | 
						|
	if [ -f "$raw_password" ]; then
 | 
						|
		if [[ $(cat "$raw_password" | grep "OPENSSH PRIVATE") ]]; then
 | 
						|
			privatekey="yes"
 | 
						|
			password="$raw_password"
 | 
						|
		else
 | 
						|
			is_password_valid
 | 
						|
		fi
 | 
						|
	else
 | 
						|
		is_password_valid
 | 
						|
	fi
 | 
						|
	format_no_quotes "$password" "password"
 | 
						|
 | 
						|
	if [ "$type" = 'sftp' ]; then
 | 
						|
		which expect > /dev/null 2>&1
 | 
						|
		check_result $? "expect command not found" "$E_NOTEXIST"
 | 
						|
	fi
 | 
						|
	if [ "$type" != 'b2' ] && [ "$type" != 'rclone' ]; then
 | 
						|
		if ! (is_ip_format_valid "$host" > /dev/null); then
 | 
						|
			host "$host" > /dev/null 2>&1
 | 
						|
			check_result $? "host connection failed" "$E_CONNECT"
 | 
						|
		fi
 | 
						|
	fi
 | 
						|
fi
 | 
						|
 | 
						|
# Perform verification if read-only mode is enabled
 | 
						|
check_hestia_demo_mode
 | 
						|
 | 
						|
#----------------------------------------------------------#
 | 
						|
#                       Action                             #
 | 
						|
#----------------------------------------------------------#
 | 
						|
 | 
						|
# Checking network connection
 | 
						|
if [ "$type" = 'ftp' ]; then
 | 
						|
	if [ -z $port ]; then
 | 
						|
		port=21
 | 
						|
	fi
 | 
						|
	fconn=$(ftpc 2>&1)
 | 
						|
	ferror=$(echo $fconn \
 | 
						|
		| grep -i -e failed -e error -e "can't" -e "not conn" -e "incorrect")
 | 
						|
	if [ -n "$ferror" ]; then
 | 
						|
		echo "Error: can't login to ftp $user@$host"
 | 
						|
		log_event "$E_CONNECT" "$ARGUMENTS"
 | 
						|
		exit "$E_CONNECT"
 | 
						|
	fi
 | 
						|
 | 
						|
	# Checking write permissions
 | 
						|
	if [ -z $path ]; then
 | 
						|
		ftmpdir="vst.bK76A9SUkt"
 | 
						|
	else
 | 
						|
		ftpc "mkdir $path" > /dev/null 2>&1
 | 
						|
		ftmpdir="$path/vst.bK76A9SUkt"
 | 
						|
	fi
 | 
						|
	ftp_result=$(ftpc "mkdir $ftmpdir" "rm $ftmpdir" | grep -v Trying)
 | 
						|
	if [ -n "$ftp_result" ]; then
 | 
						|
		echo "$ftp_result"
 | 
						|
		rm -rf $tmpdir
 | 
						|
		echo "Error: can't create $ftmpdir folder on the ftp"
 | 
						|
		log_event "$E_FTP" "$ARGUMENTS"
 | 
						|
		exit "$E_FTP"
 | 
						|
	fi
 | 
						|
fi
 | 
						|
 | 
						|
if [ "$type" = 'sftp' ]; then
 | 
						|
	if [ -z $port ]; then
 | 
						|
		port=22
 | 
						|
	fi
 | 
						|
	if [ -z $path ]; then
 | 
						|
		sftmpdir="vst.bK76A9SUkt"
 | 
						|
		sftpc "mkdir $sftmpdir" "rmdir $sftmpdir" > /dev/null 2>&1
 | 
						|
	else
 | 
						|
		if sftpc "mkdir $path" > /dev/null 2>&1; then
 | 
						|
			sftmpdir="$path/vst.bK76A9SUkt"
 | 
						|
			sftpc "mkdir $sftmpdir" "rmdir $sftmpdir" > /dev/null 2>&1
 | 
						|
		else
 | 
						|
			sftmpdir="$path/vst.bK76A9SUkt"
 | 
						|
			sftpc "mkdir $sftmpdir" "rmdir $sftmpdir" > /dev/null 2>&1
 | 
						|
		fi
 | 
						|
	fi
 | 
						|
	rc=$?
 | 
						|
	if [[ "$rc" != 0 ]]; then
 | 
						|
		case $rc in
 | 
						|
			$E_CONNECT) echo "Error: can't login to sftp $user@$host" ;;
 | 
						|
			$E_FTP) echo "Error: can't create temp folder on the sftp host" ;;
 | 
						|
		esac
 | 
						|
		log_event "$rc" "$ARGUMENTS"
 | 
						|
		exit "$rc"
 | 
						|
	fi
 | 
						|
fi
 | 
						|
 | 
						|
if [ "$type" = 'b2' ]; then
 | 
						|
	# Download b2 binary
 | 
						|
	if [ ! -f "$b2cli" ]; then
 | 
						|
		if [ "$arch" = 'aarch64' ] || [ "$arch" = 'arm64' ]; then
 | 
						|
			echo "Error: B2 binary for arm64 must be downloaded manually."
 | 
						|
			exit 3
 | 
						|
		else
 | 
						|
			wget -O $b2cli $b2lnk > /dev/null 2>&1
 | 
						|
			chmod +x $b2cli > /dev/null 2>&1
 | 
						|
		fi
 | 
						|
		if [ ! -f "$b2cli" ]; then
 | 
						|
			echo "Error: Binary download failed, b2 doesn't work as expected."
 | 
						|
			exit 3
 | 
						|
		fi
 | 
						|
	fi
 | 
						|
 | 
						|
	# Validate b2 binary
 | 
						|
	b2version="$(b2 version)"
 | 
						|
	if [[ ! "$b2version" =~ "b2 command line tool" ]]; then
 | 
						|
		echo "Error: Binary download failed, b2 doesn't work as expected."
 | 
						|
		exit 3
 | 
						|
	fi
 | 
						|
 | 
						|
	b2 clear-account > /dev/null 2>&1
 | 
						|
	b2 authorize-account "$user" "$raw_password" > /dev/null 2>&1
 | 
						|
	b2 ls --long "$host" "$user" > /dev/null 2>&1
 | 
						|
 | 
						|
	if [ $? -ne 0 ]; then
 | 
						|
		check_result "$E_CONNECT" "b2 failed to verify connection"
 | 
						|
	fi
 | 
						|
fi
 | 
						|
 | 
						|
if [ "$type" = 'rclone' ]; then
 | 
						|
	curl -s https://rclone.org/install.sh | bash /dev/null > /dev/null 2>&1
 | 
						|
	# Verify account exists
 | 
						|
	if [ ! -z "$(cat /root/.config/rclone/rclone.conf | grep "\[$host\]")" ]; then
 | 
						|
		echo "test" > /tmp/hestia-backup.txt
 | 
						|
		# Try to upload a single file
 | 
						|
		if [ -z "$path" ]; then
 | 
						|
			rclone copy /tmp/hestia-backup.txt $host:/hestia-backup.txt
 | 
						|
			rclone delete $host:/hestia-backup.txt
 | 
						|
		else
 | 
						|
			rclone copy /tmp/hestia-backup.txt $host:$path/hestia-backup.txt
 | 
						|
			rclone delete $host:$path/hestia-backup.txt
 | 
						|
		fi
 | 
						|
	else
 | 
						|
		check_result "$E_CONNECT" "Rclone config does not exist"
 | 
						|
	fi
 | 
						|
fi
 | 
						|
 | 
						|
# Adding backup host
 | 
						|
if [ $type == 'ftp' ] || [ $type = 'sftp' ]; then
 | 
						|
	new_timestamp
 | 
						|
	str="HOST='$host'\nUSERNAME='$user'\nPASSWORD='$password'\nPRIVATEKEY='$privatekey'"
 | 
						|
	str="$str\nBPATH='$path'\nPORT='$port'\nTIME='$time'\nDATE='$date'"
 | 
						|
	echo -e "$str" > $HESTIA/conf/$type.backup.conf
 | 
						|
	chmod 660 $HESTIA/conf/$type.backup.conf
 | 
						|
elif [ $type == 'b2' ]; then
 | 
						|
	new_timestamp
 | 
						|
	str="BUCKET='$host'\nB2_KEYID='$user'\nB2_KEY='$raw_password'"
 | 
						|
	str="$str\nTIME='$time'\nDATE='$date'"
 | 
						|
	echo -e "$str" > $HESTIA/conf/$type.backup.conf
 | 
						|
	chmod 660 $HESTIA/conf/$type.backup.conf
 | 
						|
elif [ $type == "rclone" ]; then
 | 
						|
	new_timestamp
 | 
						|
	str="HOST='$host'\nBPATH='$path'"
 | 
						|
	str="$str\nTIME='$time'\nDATE='$date'"
 | 
						|
	echo -e "$str" > $HESTIA/conf/$type.backup.conf
 | 
						|
fi
 | 
						|
 | 
						|
#----------------------------------------------------------#
 | 
						|
#                       Hestia                             #
 | 
						|
#----------------------------------------------------------#
 | 
						|
 | 
						|
# Update hestia.conf
 | 
						|
if [ -z "$(grep BACKUP_SYSTEM $HESTIA/conf/hestia.conf)" ]; then
 | 
						|
	echo "BACKUP_SYSTEM='$type'" >> $HESTIA/conf/hestia.conf
 | 
						|
else
 | 
						|
	bckp=$(echo "$BACKUP_SYSTEM,$type" \
 | 
						|
		| sed "s/,/\n/g" \
 | 
						|
		| sort -r -u \
 | 
						|
		| sed "/^$/d" \
 | 
						|
		| sed ':a;N;$!ba;s/\n/,/g')
 | 
						|
	sed -i "s/BACKUP_SYSTEM=.*/BACKUP_SYSTEM='$bckp'/g" $HESTIA/conf/hestia.conf
 | 
						|
fi
 | 
						|
 | 
						|
# Logging
 | 
						|
log_event "$OK" "$ARGUMENTS"
 | 
						|
 | 
						|
exit
 |