mrrfv / open-android-backup

Back up your device without vendor lock-ins, using insecure software or root. Supports encryption and compression out of the box. Works cross-platform.
http://openandroidbackup.me/
GNU General Public License v3.0
674 stars 37 forks source link

Enable multiple attempts at a password pair when creating a backup #13

Closed eltimbalino closed 1 year ago

eltimbalino commented 2 years ago

After taking the time to collect files for the backup, I was asked for my password. Then after I re-typed my password, the process failed. It would be convenient if instead of failing it looped back to the "Ask for password" function, maybe to a maximum of 3 tries in total, before failing.

mrrfv commented 2 years ago

Could you replace everything in backup.sh with the following code, and check if it works? I don't have access to a bash shell right now, but I made the changes you asked for, and I need feedback before pushing to master. Thanks.

#!/bin/bash
set -e

# Load Inquirer.sh
SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
  DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
  SOURCE="$(readlink "$SOURCE")"
  [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
done
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"

PARENT_DIR=$(dirname "$DIR")
source $DIR/inquirer-sh/list_input.sh
source $DIR/inquirer-sh/text_input.sh
# ---

# Helper functions
function wait_for_enter() {
  if [ ! -v unattended_mode ]; then
    read -p "" </dev/tty
  else
    sleep 10s
  fi
}

# "cecho" makes output messages yellow
function cecho() {
  echo $(tput setaf 11)$1$(tput init)
}

function check_adb_connection() {
  cecho "Please enable developer options on your device, connect it to your computer and set it to file transfer mode. Then, press Enter to continue."
  wait_for_enter
  adb devices > /dev/null
  cecho "If you have connected your device correctly, you should now see a message asking for access to your phone. Allow it, then press Enter to go to the last step."
  cecho "Tip: If this is not the first time you're using this script, you might not need to allow anything."
  wait_for_enter
  adb devices
  cecho "Can you see your device in the list above, and does it say 'device' next to it? If not, quit this script (ctrl+c) and try again."
}

function uninstall_companion_app() {
  cecho "Attempting to uninstall companion app."
  {
    set +e
    adb uninstall com.example.companion_app
    set -e
  } &> /dev/null
}

# Copied from stackoverflow
function retry() {
    local -r -i max_attempts="$1"; shift
    local -i attempt_num=1
    until "$@"
    do
        if ((attempt_num==max_attempts))
        then
            echo "Attempt $attempt_num failed and there are no more attempts left!"
            return 1
        else
            echo "Attempt $attempt_num failed! Trying again in $attempt_num seconds..."
            echo "Press CTRL+C to quit."
            sleep $((attempt_num++))
        fi
    done
}
# ---

check_adb_connection

if [ ! -v selected_action ]; then
  actions=( 'Backup' 'Restore' )
  list_input "What do you want to do?" actions selected_action
fi

# The companion app is required regardless of whether we're backing up the device or not,
# so we're installing it before the if statement
cecho "Linux Android Backup will install a companion app on your device, which will allow for contacts to be backed up and restored."
cecho "The companion app is open-source, and you can see what it's doing under the hood on GitHub."
if [ ! -f linux-android-backup-companion.apk ]; then
  cecho "Downloading companion app."
  # -L makes curl follow redirects
  curl -L -o linux-android-backup-companion.apk https://github.com/mrrfv/linux-android-backup/releases/download/latest/app-release.apk
else
  cecho "Companion app already downloaded."
fi
uninstall_companion_app
cecho "Installing companion app."
adb install -r linux-android-backup-companion.apk
cecho "Granting required permissions to companion app."
permissions=(
  'android.permission.READ_CONTACTS'
  'android.permission.WRITE_CONTACTS'
  'android.permission.READ_EXTERNAL_STORAGE'
)
# Grant permissions
for permission in "${permissions[@]}"; do
  adb shell pm grant com.example.companion_app $permission
done

if [ -d backup-tmp ]; then
  cecho "Cleaning up after previous backup/restore..."
  rm -rfv backup-tmp
fi

mkdir backup-tmp

if [ $selected_action = 'Backup' ]
then
  if [ ! -v archive_path ]; then
    echo "Note: Backups will first be made on the drive this script is located in, and then will be copied to the specified location."
    text_input "Please enter the backup location. Enter '.' for the current working directory." archive_path "."
  fi

  adb shell am start -n com.example.companion_app/.MainActivity
  cecho "The companion app has been opened on your device. Please press the 'Export Data' button - this will export contacts to the internal storage, allowing this script to backup them. Press Enter to continue."
  wait_for_enter
  uninstall_companion_app # we're uninstalling it so that it isn't included in the backup

  # Export apps (.apk files)
  cecho "Exporting apps."
  mkdir -p backup-tmp/Apps
  for app in $(adb shell pm list packages -3 -f)
  #   -f: see their associated file
  #   -3: filter to only show third party packages
  do
    declare output=backup-tmp/Apps
    (
      apk_path=${app%=*}                # apk path on device
      apk_path=${apk_path/package:}     # stip "package:"
      apk_base=$RANDOM$RANDOM$RANDOM.apk           # base apk name
      # e.g.:
      # app=package:/data/app/~~4wyPu0QoTM3AByZS==/com.whatsapp-iaTC9-W1lyR1FxO==/base.apk=com.whatsapp
      # apk_path=/data/app/~~4wyPu0QoTM3AByZS==/com.whatsapp-iaTC9-W1lyR1FxO==/base.apk
      # apk_base=896745.apk
      cd $output \
       && adb pull $apk_path $apk_base
    )
  done

  # Export contacts
  cecho "Exporting contacts (as vCard)."
  adb pull /storage/emulated/0/linux-android-backup-temp ./backup-tmp/Contacts
  cecho "Removing temporary files created by the companion app."
  adb shell rm -rf /storage/emulated/0/linux-android-backup-temp

  # Export internal storage
  cecho "Exporting internal storage - this will take a while."
  adb pull /storage/emulated/0 ./backup-tmp/Storage

  # Compress
  cecho "Compressing & encrypting data - this will take a while."
  # -p: encrypt backup
  # -mhe=on: encrypt headers (metadata)
  # -mx=9: ultra compression
  # -bb3: verbose logging
  # -sdel: delete files after compression
  # The undefined variable is set by the user 
  retry 3 7z a -p$archive_password -mhe=on -mx=9 -bb3 -sdel $archive_path/linux-android-backup-$(date +%m-%d-%Y-%H-%M-%S).7z backup-tmp/*

  cecho "Backed up successfully."
  rm -rf backup-tmp > /dev/null
elif [ $selected_action = 'Restore' ]
then
  if [ ! -v archive_path ]; then
    text_input "Please provide the location of the backup archive to restore (drag-n-drop):" archive_path
  fi

  cecho "Extracting archive."
  7z x $archive_path # -obackup-tmp isn't needed

  # Restore applications
  cecho "Restoring applications."
  # We don't want a single app to break the whole script
  set +e
  find ./backup-tmp/Apps -type f -name "*.apk" -exec adb install {} \;
  set -e

  # Restore internal storage
  cecho "Restoring internal storage."
  adb push ./backup-tmp/Storage/* /storage/emulated/0

  # Restore contacts
  cecho "Pushing backed up contacts to device."
  adb push ./backup-tmp/Contacts /storage/emulated/0/Contacts_Backup

  cecho "Data restored!"
  cecho "WARNING: Contacts have been only copied to your device. You need to open the companion app to restore them."
fi

cecho "If this project helped you, please star the GitHub repository. It lets me know that there are people using this script and I should continue working on it."
eltimbalino commented 2 years ago

Yes, I'll give that a go when I get back home. But I'm away for about two weeks.

Thanks for your great coding,

Tim.

On Sat, 4 Jun 2022, 02:39 mrrfv, @.***> wrote:

Could you replace everything in backup.sh with the following code? I don't have access to a bash shell right now, but I made the changes you asked for, and I need feedback before pushing to master. Thanks.

!/bin/bashset -e

Load Inquirer.sh

SOURCE="${BASH_SOURCE[0]}"while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" SOURCE="$(readlink "$SOURCE")" [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was locateddone DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"

PARENT_DIR=$(dirname "$DIR")source $DIR/inquirer-sh/list_input.shsource $DIR/inquirer-sh/text_input.sh# ---

Helper functionsfunction wait_for_enter() {

if [ ! -v unattended_mode ]; then read -p "" </dev/tty else sleep 10s fi }

"cecho" makes output messages yellowfunction cecho() {

echo $(tput setaf 11)$1$(tput init) } function check_adb_connection() { cecho "Please enable developer options on your device, connect it to your computer and set it to file transfer mode. Then, press Enter to continue." wait_for_enter adb devices > /dev/null cecho "If you have connected your device correctly, you should now see a message asking for access to your phone. Allow it, then press Enter to go to the last step." cecho "Tip: If this is not the first time you're using this script, you might not need to allow anything." wait_for_enter adb devices cecho "Can you see your device in the list above, and does it say 'device' next to it? If not, quit this script (ctrl+c) and try again." } function uninstall_companion_app() { cecho "Attempting to uninstall companion app." { set +e adb uninstall com.example.companion_app set -e } &> /dev/null }

Copied from stackoverflowfunction retry() {

local -r -i max_attempts="$1"; shift
local -i attempt_num=1
until "$@"
do
    if ((attempt_num==max_attempts))
    then
        echo "Attempt $attempt_num failed and there are no more attempts left!"
        return 1
    else
        echo "Attempt $attempt_num failed! Trying again in $attempt_num seconds..."
        echo "Press CTRL+C to quit."
        sleep $((attempt_num++))
    fi
done

}# ---

check_adb_connection if [ ! -v selected_action ]; then actions=( 'Backup' 'Restore' ) list_input "What do you want to do?" actions selected_actionfi

The companion app is required regardless of whether we're backing up the device or not,# so we're installing it before the if statement

cecho "Linux Android Backup will install a companion app on your device, which will allow for contacts to be backed up and restored." cecho "The companion app is open-source, and you can see what it's doing under the hood on GitHub."if [ ! -f linux-android-backup-companion.apk ]; then cecho "Downloading companion app."

-L makes curl follow redirects

curl -L -o linux-android-backup-companion.apk https://github.com/mrrfv/linux-android-backup/releases/download/latest/app-release.apkelse cecho "Companion app already downloaded."fi uninstall_companion_app cecho "Installing companion app." adb install -r linux-android-backup-companion.apk cecho "Granting required permissions to companion app." permissions=( 'android.permission.READ_CONTACTS' 'android.permission.WRITE_CONTACTS' 'android.permission.READ_EXTERNAL_STORAGE' )# Grant permissionsfor permission in "${permissions[@]}"; do adb shell pm grant com.example.companion_app $permissiondone if [ -d backup-tmp ]; then cecho "Cleaning up after previous backup/restore..." rm -rfv backup-tmpfi

mkdir backup-tmp if [ $selected_action = 'Backup' ]then if [ ! -v archive_path ]; then echo "Note: Backups will first be made on the drive this script is located in, and then will be copied to the specified location." text_input "Please enter the backup location. Enter '.' for the current working directory." archive_path "." fi

adb shell am start -n com.example.companion_app/.MainActivity cecho "The companion app has been opened on your device. Please press the 'Export Data' button - this will export contacts to the internal storage, allowing this script to backup them. Press Enter to continue." wait_for_enter uninstall_companion_app # we're uninstalling it so that it isn't included in the backup

Export apps (.apk files)

cecho "Exporting apps." mkdir -p backup-tmp/Apps for app in $(adb shell pm list packages -3 -f)

-f: see their associated file

-3: filter to only show third party packages

do declare output=backup-tmp/Apps ( apk_path=${app%=*} # apk path on device apk_path=${apk_path/package:} # stip "package:" apk_base=$RANDOM$RANDOM$RANDOM.apk # base apk name

e.g.:

  # app=package:/data/app/~~4wyPu0QoTM3AByZS==/com.whatsapp-iaTC9-W1lyR1FxO==/base.apk=com.whatsapp
  # apk_path=/data/app/~~4wyPu0QoTM3AByZS==/com.whatsapp-iaTC9-W1lyR1FxO==/base.apk
  # apk_base=896745.apk
  cd $output \
   && adb pull $apk_path $apk_base
)

done

Export contacts

cecho "Exporting contacts (as vCard)." adb pull /storage/emulated/0/linux-android-backup-temp ./backup-tmp/Contacts cecho "Removing temporary files created by the companion app." adb shell rm -rf /storage/emulated/0/linux-android-backup-temp

Export internal storage

cecho "Exporting internal storage - this will take a while." adb pull /storage/emulated/0 ./backup-tmp/Storage

Compress

cecho "Compressing & encrypting data - this will take a while."

-p: encrypt backup

-mhe=on: encrypt headers (metadata)

-mx=9: ultra compression

-bb3: verbose logging

-sdel: delete files after compression

The undefined variable is set by the user

retry 3 7z a -p$archive_password -mhe=on -mx=9 -bb3 -sdel $archive_path/linux-android-backup-$(date +%m-%d-%Y-%H-%M-%S).7z backup-tmp/*

cecho "Backed up successfully." rm -rf backup-tmp > /dev/nullelif [ $selected_action = 'Restore' ]then if [ ! -v archive_path ]; then text_input "Please provide the location of the backup archive to restore (drag-n-drop):" archive_path fi

cecho "Extracting archive." 7z x $archive_path # -obackup-tmp isn't needed

Restore applications

cecho "Restoring applications."

We don't want a single app to break the whole script

set +e find ./backup-tmp/Apps -type f -name "*.apk" -exec adb install {} \; set -e

Restore internal storage

cecho "Restoring internal storage." adb push ./backup-tmp/Storage/* /storage/emulated/0

Restore contacts

cecho "Pushing backed up contacts to device." adb push ./backup-tmp/Contacts /storage/emulated/0/Contacts_Backup

cecho "Data restored!" cecho "WARNING: Contacts have been only copied to your device. You need to open the companion app to restore them."fi

cecho "If this project helped you, please star the GitHub repository. It lets me know that there are people using this script and I should continue working on it."

— Reply to this email directly, view it on GitHub https://github.com/mrrfv/linux-android-backup/issues/13#issuecomment-1146163080, or unsubscribe https://github.com/notifications/unsubscribe-auth/AICRE5ZP3X4VLDSIT6MCLHDVNIYLFANCNFSM5XPHULTA . You are receiving this because you authored the thread.Message ID: @.***>