#!/bin/bash # _______________ ______ ______ ______ # ___ ____/__ /_____ __________ /____ /_______ _________ /__ # __ /_ __ /_ __ `/_ ___/_ __ \_ __ \ __ `/ ___/_ //_/ # _ __/ _ / / /_/ /_(__ )_ / / / /_/ / /_/ // /__ _ ,< # /_/ /_/ \__,_/ /____/ /_/ /_//_.___/\__,_/ \___/ /_/|_| # "Backup, restore, and share your iOS setups." # Notes: # ** This is a dangerous script if something goes wrong. ** # Should be using printf instead of 'echo -e' # "set -e" should be used instead of || (at least we have some fancy debug messages) # DO NOT USE "cp -f" WHEN REPLACING SYSTEM FILES. Its dangerous, but yet no other solution comes to mind. DEBUG="echo" # set to "echo" to avoid running commands that edit the filesystem. FLASHBACKDIR="/Library/FlashBack" BACKUPNAME=$(date +%m-%d-%y-`cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 8 | head -n 1`) BACKUPLOCATION= STATUS= SELECTLOCATION= AUTOBACKUPLOCATION= DELETEBACKUP= DELETESELECT= BKPVERSION="v2" PKGVERSION="1.7" # report(){ # report to dev example function # echo "$foo-bar has went wrong" # echo "Report the dev if this happens more than once" # exit 1 ; fi ;} # Kill the script killIfIdle(){ #Flashback checks for timeouts and kills itsself if idle for too long if [[ $? -eq 142 ]]; then echo -e "\n\e[0;100m[!]\e[0m \e[104mTo save battery, FlashBack has stopped itself due to lack of activity!\e[0m" rm -r -f $FLASHBACKDIR/tmp &>/dev/null #clear temp/working files exit 0 #kills itself fi } prgmNav(){ if [[ $LASTINPUT = "QUIT" ]]; then echo -e "\n\e[0;100m[!]\e[0m \e[104mThanks for using FlashBack!\e[0m" rm -r -f $FLASHBACKDIR/tmp &>/dev/null #clear temp/working files exit 1 #kills child function fi if [[ $LASTINPUT = "BACK" ]]; then echo -e "\n\e[0;100m[!]\e[0m \e[104mNavigating Back...\e[0m" rm -r -f $FLASHBACKDIR/tmp &>/dev/null #clear temp/working files displayMenu fi } tests() { if [ ! $(id -u) = "0" ] ; then # root check echo -e "\a\n\e[0;100m[*]\e[0m \e[1;31mMust be \e[4;37mroot\e[0m \n\e[1;31m\e[0;100m[*]\e[0m Current User is\e[0m \e[4;37m$USER\e[0m\n" exit 1 ; fi if [ ! -d $FLASHBACKDIR/Backups ] ; then # check for /Library/Flashback/Backups, ask the user to create it if it doesn't exist. echo -e "\n\e[0;100m[*]\e[0m\e[1;31m Directory $FLASHBACKDIR/Backups doesn't exist!\e[0m \n\n\e[1;37mShall it be created?\e[0m" read -rp " [y/N] " -t 15 RESPONSE # https://stackoverflow.com/questions/3231804/in-bash-how-to-add-are-you-sure-y-n-to-any-command-or-alias LASTINPUT=$RESPONSE prgmNav && killIfIdle if [[ "$RESPONSE" =~ ^([yY][eE][sS]|[yY])+$ ]] # Couldn't remember the expression for this. then # Do it. mkdir -p $FLASHBACKDIR/Backups || exit 1 else # or Abort. echo -e "\n\e[1;97m\"Run away! Run away!\" \e[0m\n" exit 1; fi; fi ;} # -----------------------\ pause(){ read -sp "`echo -e '\n\e[0;100m[!]\e[0m \e[104mPress enter to continue...\e[0m'`" -t 10 # read has a timeout function that could be used to advance the script by its own. killIfIdle echo -e "\n" ; displayMenu } # -----------------------\ shopt -s extglob # "Shell option set extglob" https://www.linuxjournal.com/content/bash-extended-globbing # -----------------------\ one() { # Function that backs-up the current preferences set -f # "Disable file name generation (globbing)." TEMPBACKUPNAME= read -p "`echo -e '\n\e[0;100m[!]\e[0m \e[104mEnter backup name...\e[0m'` > " -t 30 TEMPBACKUPNAME # BACKUPNAME has the date LASTINPUT=$TEMPBACKUPNAME prgmNav && killIfIdle TEMPBACKUPNAME=${TEMPBACKUPNAME//[^a-zA-Z0-9-.]/} # Stop bad inputs if [[ $TEMPBACKUPNAME = "" ]] ; then echo -e "\n\e[0;100m[!]\e[0m \e[104mBad or no input... Using $BACKUPNAME instead\e[0m" else TEMPBACKUPNAME=${TEMPBACKUPNAME//[^a-zA-Z0-9-.]/} BACKUPNAME=$TEMPBACKUPNAME; fi set +f BACKUPLOCATION=$FLASHBACKDIR/Backups/$BACKUPNAME mkdir -p $BACKUPLOCATION/{Preferences,SBFolder,AutoWall} || STATUS="mkdir failed" echo -e "\n\e[0;100m[!]\e[0m \e[104mCopying to $BACKUPLOCATION\e[0m" cp -rf "/var/mobile/Library/Preferences/"!(com.apple*|com.saurik*|ckkeyrolld|nfcd|UITextInputContextIdentifiers|.GlobalPreferences).plist $BACKUPLOCATION/Preferences/ || STATUS="cp failed" #copy all non-apple Plists to Preference folder within backup haha cp -rf "/var/mobile/Library/Preferences/"*(*.jpg|*.png|*.gif) $BACKUPLOCATION/Preferences/ &>/dev/null #copy all images to Preference folder within backup cp -rf /var/mobile/Library/SpringBoard/@(*Icon*|*Background*|SB*) $BACKUPLOCATION/SBFolder/ || STATUS="cp failed" #copy IconState Plist to SBFolder folder within backup if [[ -d /var/mobile/Media/AutoWall/ ]] then cp -rf "/var/mobile/Media/AutoWall/"* "$BACKUPLOCATION/AutoWall/" fi touch $BACKUPLOCATION/$BKPVERSION # ||||||||||||||||||||||||||||||||||| if [[ ! $STATUS = "" ]] ; then echo -e "\a\n\e[0;100m[*]\e[0m \e[1;31mSomething went wrong: $STATUS \e[0m\n" exit 1 ; fi # TODO MCApollo: Make a report to developer function. # ////////////////////////////////// echo -e "\n\e[104m Success! \e[0m \n" pause ;} # -----------------------\ two() { echo -e "\n\e[104m Available Backups: \e[0m \n" for i in $(ls $FLASHBACKDIR/Backups/ || echo "#CRTL-C_to_exit#") ; do # Find and sed are not default commands- can't exclude files. echo -e " \e[100m---->\e[0m \e[33m$i\e[0m" ; done SELECTBACKUP= while [[ $SELECTBACKUP = "" ]] ; do set -f unset RESET read -p "`echo -e '\n\e[0;100m[!]\e[0m \e[104mSelect Backup\e[0m'` -> " -t 20 SELECTBACKUP LASTINPUT=$SELECTBACKUP prgmNav && killIfIdle SELECTBACKUP=${SELECTBACKUP//[^a-zA-Z0-9-.]/} if [[ $SELECTBACKUP = "" ]] ; then echo -e "\n\e[0;100m[*]\e[0m \e[1;31mBad or no input!\e[0m\n" RESET="YES"; fi if [[ ! -d $FLASHBACKDIR/Backups/$SELECTBACKUP ]] && [[ -z ${RESET+x} ]] ; then echo -e "\n\e[0;100m[*]\e[0m \e[1;31mNo backup with that name exists!\e[0m" SELECTBACKUP="" ; fi set +f ; done SELECTLOCATION=$FLASHBACKDIR/Backups/$SELECTBACKUP if [ -f $SELECTLOCATION/$BKPVERSION ] then echo -e "\n\e[0;100m[!]\e[0m \e[104mIt's recommended to make an Autobackup before you restore.\e[0m" echo -e "\n\e[0;100m[!]\e[0m \e[104mWould you like to do that now?\e[0m" read -rp " [y/N] " -t 15 RESPONSE # https://stackoverflow.com/questions/3231804/in-bash-how-to-add-are-you-sure-y-n-to-any-command-or-alias if [[ "$RESPONSE" =~ ^([yY][eE][sS]|[yY])+$ ]] # Couldn't remember the expression for this. then # Do it. AUTOBACKUPLOCATION=$FLASHBACKDIR/Backups/AutoBackup_$(date '+%d-%m-%Y_%H:%M:%S') echo -e "\n\e[0;100m[!]\e[0m \e[104mMoving current Preferences to $AUTOBACKUPLOCATION\e[0m" mkdir -p $AUTOBACKUPLOCATION/{Preferences,SBFolder,AutoWall} || STATUS="mkdir failed" cp "/var/mobile/Library/Preferences/"!(com.apple*|com.saurik*|ckkeyrolld|nfcd|UITextInputContextIdentifiers).plist $AUTOBACKUPLOCATION/Preferences || STATUS="cp failed" cp -rf "/var/mobile/Library/Preferences/"*(*.jpg|*.png|*.gif) $BACKUPLOCATION/Preferences/ || STATUS="cp failed" cp -r /var/mobile/Library/SpringBoard/@(*Icon*|*Background*|SB*) $AUTOBACKUPLOCATION/SBFolder/ || STATUS="cp failed" if [[ -d /var/mobile/Media/AutoWall/ ]] then cp -rf "/var/mobile/Media/AutoWall/"* "$AUTOBACKUPLOCATION/AutoWall/" || STATUS="cp failed" fi touch $AUTOBACKUPLOCATION/$BKPVERSION fi echo -e "\n\e[0;100m[!]\e[0m \e[104mCopying Backup to appropriate system directories...\e[0m" cp -r $SELECTLOCATION/Preferences/* /var/mobile/Library/Preferences/ || STATUS="cp failed" cp -r $SELECTLOCATION/SBFolder/* /var/mobile/Library/SpringBoard/ || STATUS="cp failed" if [[ -d $SELECTLOCATION/AutoWall/ ]] then cp -rf "$SELECTLOCATION/AutoWall/"* "/var/mobile/Media/AutoWall/" &>/dev/null fi echo -e "\n\e[0;100m[*]\e[0m \e[104mRebuilding image cache...\e[0m" uicache || STATUS="uicache failed" recache --no respring &>/dev/null || echo -e "\n\e[0;100m[*]\e[0m \e[104mAnemone not installed. Recache ignored.\e[0m" killall cfprefsd #Clear settings caches - thanks to Grant/NewD if [[ ! $STATUS = "" ]] ; then echo -e "\a\n\e[0;100m[*]\e[0m \e[1;31mSomething went wrong: $STATUS \e[0m\n" exit 1 ; fi # TODO: Make a report to developer function. if [ -z ${SSH_TTY+x} ] ; then # Should we kill SpringBoard or not? # This is NewTerm echo -e "\a\n\e[0;100m[!]\e[0m \e[1;31mKilling SpringBoard \e[0m\n\n\e[0;100m Thank you for using Flashback! \e[0m" killall -9 SpringBoard && exit 0 # Kill the script. else # This is a SSH Session echo -e "\a\n\e[0;100m[!]\e[0m \e[1;31mKilling SpringBoard \e[0m\n\n\e[0;100m Thank you for using Flashback! \e[0m" killall -9 SpringBoard fi else echo -e "\n\e[0;100m[*]\e[0m \e[1;31mIncompatible Backup Version!\e[0m" fi pause ;} three(){ # Function that deletes backups echo -e "\n\e[104m Available Backps: \e[0m \n" for i in $(ls $FLASHBACKDIR/Backups/ || echo "#CRTL-C_to_exit#") ; do # Find and sed are not default commands- can't exclude files. echo -e " \e[100m---->\e[0m \e[33m$i\e[0m" ; done DELETEBACKUP= while [[ $DELETEBACKUP = "" ]] ; do unset RESET set -f read -p "`echo -e '\n\e[0;100m[!]\e[0m \e[104mSelect Backup\e[0m'` -> " -t 30 DELETEBACKUP LASTINPUT=$DELETEBACKUP prgmNav && killIfIdle DELETELOCATION=$FLASHBACKDIR/Backups/$DELETEBACKUP #DELETEBACKUP=${DELETEBACKUP//[^a-zA-Z0-9-.]/} if [[ $DELETEBACKUP = "" ]]; then echo -e "\n\e[0;100m[*]\e[0m \e[1;31mBad or no input!\e[0m" RESET="YES" ; fi if [[ ! -d $DELETELOCATION ]] && [[ -z ${RESET+x} ]] ; then echo -e "\n\e[0;100m[*]\e[0m \e[1;31mNo backup with that name exists!\e[0m" DELETEBACKUP="" ; fi set +f ; done DELETECP= echo -e "\n\e[0;100m[!]\e[0m\e[1;31m Are you REALLY sure you want to delete this backup?\e[0m\n \n\e[1;37mType \"FLASHBACK\" exactly the way it is if you're sure!\e[0m\n" read -p "`echo -e ' \e[0;100m---->\e[0m \e[1;31m'` " -t 45 DELETECP LASTINPUT=$DELETECP prgmNav && killIfIdle if [[ $DELETECP = "FLASHBACK" ]] then echo -e "\n\e[0;100m[!]\e[0m \e[104mDeleting $DELETELOCATION\e[0m" rm -r $DELETELOCATION else echo -e "\n\e[0;100m[!]\e[0m \e[104mNot deleting $DELETELOCATION\e[0m"; fi pause ;} four(){ # Function that deletes autobackups made in function two DELETEAB= echo -e "\n\e[0;100m[!]\e[0m\e[1;31m Are you REALLY sure you want to delete all AutoBackups?\e[0m\n \n\e[1;37mType \"FLASHBACK\" exactly the way it is if you're sure!\e[0m\n" read -p "`echo -e ' \e[0;100m---->\e[0m \e[1;31m'` " -t 45 DELETEAB LASTINPUT=$DELETEAB prgmNav && killIfIdle if [[ $DELETEAB = "FLASHBACK" ]] then echo -e "\n\e[0;100m[!]\e[0m \e[104mDeleting all autobackups...\e[0m" rm -r $FLASHBACKDIR/Backups/AutoBackup* else echo -e "\n\e[0;100m[!]\e[0m \e[104mExiting...\e[0m"; fi pause ;} five(){ # I'm not going to painstakingly fix this. You gotta do that yourself. - Apollo if [ ! -d /var/mobile/Documents/FlashBackDEBs/ ] ; then # check for /Library/Flashback/Backups, ask the user to create it if it doesn't exist. echo -e "\n\e[0;100m[*]\e[0m\e[1;31m Directory /var/mobile/Documents/FlashBackDEBs/ doesn't exist!\e[0m \n\n\e[1;37mShall it be created?\e[0m" read -rp " [y/N] " -t 15 RESPONSE # https://stackoverflow.com/questions/3231804/in-bash-how-to-add-are-you-sure-y-n-to-any-command-or-alias LASTINPUT=$RESPONSE prgmNav && killIfIdle if [[ "$RESPONSE" =~ ^([yY][eE][sS]|[yY])+$ ]] # Couldn't remember the expression for this. then # Do it. mkdir -p /var/mobile/Documents/FlashBackDEBs/ || exit 1 else # or Abort. echo -e "\n\e[1;97m\"Run away! Run away!\" \e[0m\n" exit 1; fi; fi ; echo -e "\n\e[104m Available Backps: \e[0m \n" for i in $(ls $FLASHBACKDIR/Backups/ || echo "#CRTL-C_to_exit#") ; do # Find and sed are not default commands- can't exclude files. echo -e " \e[100m---->\e[0m \e[33m$i\e[0m" ; done read -p "`echo -e '\n\e[0;100m[!]\e[0m \e[104mChoose a Backup\e[0m'` > " -t 10 PACKAGEBACKUP LASTINPUT=$PACKAGEBACKUP prgmNav && killIfIdle read -p "`echo -e '\n\e[0;100m[!]\e[0m \e[104mEnter Your UserName\e[0m'` > " -t 20 USERNAME LASTINPUT=$USERNAME prgmNav && killIfIdle read -p "`echo -e '\n\e[0;100m[!]\e[0m \e[104mEnter A Short Description\e[0m'` > " -t 20 USERDESC LASTINPUT=$USERDESC prgmNav && killIfIdle # TODO: MCApollo # Clean the input, wildcard (*) makes it game over. echo -e "\n\e[0;100m~~~~~~~~~~~~~~~~~~~~~~~~~~~\e[0m\n\nWould you like to specify dependancies?\nIf so, it's recommended to use iCleaner Pro to clean up unused preference files before you start.\n\n\e[0;100mAutomatic:\e[0m You select which packages are dependancies, for a streamlined installation.\nThis is highly recommended if you intend to host your setup on a repo, or share with other users.\n\n\e[0;100mManual:\e[0m Dependancies are not set for users, they must install the tweaks themselves.\nThis is recommended if you plan to use this setup personally.\n\n\e[0;100m~~~~~~~~~~~~~~~~~~~~~~~~~~~\e[0m" read -p "`echo -e '\n\e[0;100m[!]\e[0m \e[104mWould you like to proceed in automatic mode? (yes/no)\e[0m'` > " -t 15 AUTOMODE LASTINPUT=$AUTOMODE prgmNav && killIfIdle if [[ $AUTOMODE = "yes" ]] then read -p "`echo -e '\n\e[0;100m~~~~~~~~~~~~~~~~~~~~~~~~~~~\e[0m\n\n\e[0;100m[!]\e[0m Staring automatic mode. A list of installed packages will appear in a moment.\nUse that list to select which packages are dependancies. \e[104mPress enter to proceed.\e[0m'` > " -t 20 killIfIdle apt-mark auto "gsc*" &> /dev/null || STATUS="apt-mark failed" # For some reason, apt likes to seg fault. Maybe due to too much memory is being used? echo -e "\n\e[0;100m~~~~~~~~~~~~~~~~~~~~~~~~~~~\e[0m" apt-mark showmanual || STATUS="SEG FAULT" # TODO: MCApollo # Copy paste the STATUS check and exit if seg fault. # Or better yet, the exit code is 139 if it's a seg fault. # Use the exit code to see if apt seg fault; exit or try again once. read -p "`echo -e '\e[0;100m~~~~~~~~~~~~~~~~~~~~~~~~~~~~\e[0m\n\e[0;100m[!]\e[0m \e[104mPlease copy all desired dependancies from above EXACTLY as they are displayed. Separate them with a comma and a space (, )\e[0m'` > " -t 600 USERSETDEPENDENCIES LASTINPUT=$USERSETDEPENDENCIES prgmNav && killIfIdle fi mkdir $FLASHBACKDIR/tmp WORKINGDIR=$FLASHBACKDIR/tmp/$PACKAGEBACKUP mkdir $WORKINGDIR mkdir $WORKINGDIR/DEBIAN mkdir -p $WORKINGDIR$FLASHBACKDIR/Backups/$PACKAGEBACKUP # Correct answer; you're hard-coding /Library/FlashBack cp -r $FLASHBACKDIR"/Backups/"$PACKAGEBACKUP/!(control*) $WORKINGDIR/Library/FlashBack/Backups/$PACKAGEBACKUP/ if [[ $autoMode = "yes" ]] then cat > $WORKINGDIR/DEBIAN/control < $WORKINGDIR/DEBIAN/control < /dev/null echo -e "\e[0;100m[!]\e[0m Creating DEB..." cp $WORKINGDIR.deb "/var/mobile/Documents/FlashBackDEBs/" rm -r -f $FLASHBACKDIR/tmp echo -e "\n\e[0;100m[!]\e[0mThe DEB can be found in /var/mobile/Documents/FlashBackDEBs/com.$USERNAME.$PACKAGEBACKUP.deb" # TODO MCApollo # Use dpkg-deb or dpkg to make sure it's a vaild package. (Maybe extract it?) pause } six(){ #Provide Users a way to make any backup compatible with Latest version echo -e "\n\e[91m [!] There is a chance\n that backing up an \n old backup can cause\n unwanted results. If \n you experience issues\n restoring to an updated\n backup, use the most\n recent autobackup to\n revert changes! \e[0m \n" echo -e "\n\e[91m If you experience no\n issues after restoring,\n please overwrite the\n updated backup to ensure\n the best experience! \e[0m \n" echo -e "\n\e[104m Available Backups: \e[0m \n" for i in $(ls $FLASHBACKDIR/Backups/ || echo "#CRTL-C_to_exit#") ; do # Find and sed are not default commands- can't exclude files. echo -e " \e[100m---->\e[0m \e[33m$i\e[0m" ; done UPDATEBACKUP= while [[ $UPDATEBACKUP = "" ]] ; do set -f unset RESET read -p "`echo -e '\n\e[0;100m[!]\e[0m \e[104mSelect Backup\e[0m'` -> " -t 20 UPDATEBACKUP prgmNav && killIfIdle UPDATEBACKUP=${UPDATEBACKUP//[^a-zA-Z0-9-.]/} if [[ $UPDATEBACKUP = "" ]] ; then echo -e "\n\e[0;100m[*]\e[0m \e[1;31mBad or no input!\e[0m\n" RESET="YES"; fi if [[ ! -d $FLASHBACKDIR/Backups/$UPDATEBACKUP ]] && [[ -z ${RESET+x} ]] ; then echo -e "\n\e[0;100m[*]\e[0m \e[1;31mNo backup with that name exists!\e[0m" UPDATEBACKUP="" ; fi set +f ; done UPDATELOCATION=$FLASHBACKDIR/Backups/$UPDATEBACKUP touch $UPDATELOCATION/$BKPVERSION if [ -f $UPDATELOCATION/$BKPVERSION ] then echo -e "\n\e[0;100m[*]\e[0m \e[104mSuccess!\e[0m" echo -e "\n\e[0;100m[*]\e[0m \e[104mYour Backup has been updated to work with this version of FlashBack!\e[0m" fi pause } readme(){ echo -e "\n\e[1;31m When inputting backup\n names,use plaintext\n and numbers ONLY!\n Special characters\n may result in dangerous\n side effects!\e[0m\n" echo -e "\n\e[1;31m PLEASE kill FlashBack\n Properly! While there\n are failsafes in place,\n it is still possible\n for backgrounding to\n fall between the cracks!\e[0m\n" echo -e "\n\e[1;31m To go back to the menu\n from any screen, just\n type 'BACK'.\n To exit FlashBack from\n any screen, type 'QUIT'\n" echo -e "\n\e[1;31m Please make sure you\n watch the video on how\n to use FlashBack in\n the Cydia depiction\n if you're lost!\n" echo -e "\n\e[1;31m If FlashBack has\n helped you, or if you\n appreciate my work,\n consider donating with\n the link in the cydia\n depiction!\n" pause } # TODO Idea: MCApollo # Get the amount of $COLUMNS and $LINES, scale the UI base on that information # For example, (( ~ X $COLUMNS)) into a VAR and then echo $VAR instead of hard-coding "~~~~~~~~~~~" show_menus() { clear echo -e " _____________________ \n | ___ ___ |\n | | __| | _ ) |\n | | _| | _ \ |\n | |_| LASH |___/ACK |\n |_____________________|" echo -e "\n\e[1;32m Please read the FAQ\n in the Cydia package\n depiction!\n" echo -e "\e[0;100m[1.]\e[0m \e[33mBackup Current Preferences\e[0m" echo -e "\e[0;100m[2.]\e[0m \e[33mRestore Backup\e[0m" echo -e "\e[0;100m[3.]\e[0m \e[33mDelete Backups\e[0m" echo -e "\e[0;100m[4.]\e[0m \e[33mDelete AutoBackups\e[0m" echo -e "\e[0;100m[5.]\e[0m \e[33mPackage Backup to DEB\e[0m" echo -e "\e[0;100m[6.]\e[0m \e[33mUpdate Old Backup\e[0m" echo -e "\e[0;100m[R.]\e[0m \e[91mREADME\e[0m" echo -e "\e[0;100m[Q.]\e[0m \e[91mQuit\e[0m" } read_options(){ local choice read -p "`echo -e '\e[0;100m[!]\e[0m \e[104mEnter choice [1 - 6]\e[0m'` > " -t 15 choice killIfIdle case $choice in 1) one ;; 2) two ;; 3) three ;; 4) four ;; 5) five;; 6) six;; R) readme;; Q) exit 0;; *) echo "Invalid Selection!" && sleep 2 esac } displayMenu(){ clear cp &>/dev/null shopt -s extglob show_menus echo " " read_options } tests while true do displayMenu done