Last active
June 24, 2023 08:16
-
-
Save AutonomousCat/54830965d9a06bba9fa8058cf6ed5a70 to your computer and use it in GitHub Desktop.
A cross-platform Python (3.7+) script that uses ADB to automatically pull Aegis Authenticator backups from your Android device. Designed to run in the background, so you can set it up once and forget about it.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from os import path, listdir | |
from time import sleep | |
from subprocess import check_output, Popen, PIPE, CalledProcessError | |
import logging | |
logging.basicConfig( | |
level=logging.INFO, | |
format='[%(asctime)s][%(levelname)s] %(message)s', | |
datefmt='%m-%d %H:%M', | |
handlers=[logging.StreamHandler(), logging.FileHandler("backup.log")] | |
) | |
log = logging.getLogger(__name__) | |
config = { | |
'source_dir': '/storage/self/primary/Aegis/', # use ADB shell to examine your device's directory structure | |
'destination_dir': 'C:/Users/me/Documents/Aegis-Backup/', | |
'check_interval': 15 * 60 # 15 minutes | |
} | |
class AegisBackup: | |
def __init__(self, **kwargs): | |
self.__dict__.update(kwargs) | |
self.adb_pull = None | |
def backup(self): | |
try: | |
source_files = check_output(['adb', 'shell', f'ls -t {self.source_dir}aegis-backup-*.json'], text=True).split() | |
log.debug(f'Output of "adb shell ls -t": {", ".join(source_files)}') | |
if len(source_files) > 0: | |
latest_source_file = path.split(source_files[0])[-1] | |
if latest_source_file not in listdir(self.destination_dir): | |
self.adb_pull = Popen(['adb', 'pull', f'{self.source_dir}{latest_source_file}', self.destination_dir], stdout=PIPE, stderr=PIPE, text=True) | |
adb_pull_output, adb_pull_errors = self.adb_pull.communicate() | |
if self.adb_pull.returncode == 0: | |
log.info(f'New backup file pulled: "{latest_source_file}"') | |
log.debug(f'Output of "adb pull": {adb_pull_output.strip()}') | |
else: | |
log.error(f'Backup failed with error: {adb_pull_errors.strip()}') | |
raise CalledProcessError(self.adb_pull.returncode, self.adb_pull.args, output=adb_pull_output, stderr=adb_pull_errors) | |
else: | |
log.debug(f'Source file "{latest_source_file}" is already in "{self.destination_dir}"') | |
else: | |
log.debug(f'No files found in: "{self.source_dir}"') | |
except CalledProcessError as e: | |
log.error(f'Backup failed with error: {e.output.strip()}') | |
self.adb_pull = None | |
def run(self): | |
log.info('Started.') | |
try: | |
while True: | |
self.backup() | |
sleep(self.check_interval) | |
except KeyboardInterrupt: | |
log.info('Stopping. Please wait for any remaining "adb pull" operation to complete.') | |
while self.adb_pull and not self.adb_pull.poll(): | |
time.sleep(1) | |
log.debug('Stopped.') | |
if __name__ == '__main__': | |
backup = AegisBackup(**config) | |
backup.run() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment