diff --git a/scripts/auto_repairs.py b/scripts/auto_repairs.py index 18ee80cc..33e8e100 100644 --- a/scripts/auto_repairs.py +++ b/scripts/auto_repairs.py @@ -40,7 +40,7 @@ BASE_MENUS = { MenuEntry('Enable System Restore', 'auto_system_restore_enable'), MenuEntry('Set System Restore Size', 'auto_system_restore_set_size'), MenuEntry('Create System Restore', 'auto_system_restore_create'), - #MenuEntry('Backup Browsers', #TODO), + MenuEntry('Backup Browsers', 'auto_backup_browser_profiles'), MenuEntry('Backup Power Plans', 'auto_backup_power_plans'), MenuEntry('Backup Registry', 'auto_backup_registry'), ), @@ -90,6 +90,8 @@ BASE_MENUS = { if __name__ == '__main__': try: wk.repairs.win.run_auto_repairs(BASE_MENUS) + except KeyboardInterrupt: + wk.std.abort() except SystemExit: raise except: #pylint: disable=bare-except diff --git a/scripts/wk/io.py b/scripts/wk/io.py index 2cbbef46..3e2c8d04 100644 --- a/scripts/wk/io.py +++ b/scripts/wk/io.py @@ -113,6 +113,16 @@ def delete_item(path, force=False, ignore_errors=False): os.remove(path) +def get_path_obj(path, expanduser=True, resolve=True): + """Get based on path, returns pathlib.Path.""" + path = pathlib.Path(path) + if expanduser: + path = path.expanduser() + if resolve: + path = path.resolve() + return path + + def non_clobber_path(path): """Update path as needed to non-existing path, returns pathlib.Path.""" LOG.debug('path: %s', path) diff --git a/scripts/wk/repairs/win.py b/scripts/wk/repairs/win.py index 7ef0e455..fde6f130 100644 --- a/scripts/wk/repairs/win.py +++ b/scripts/wk/repairs/win.py @@ -12,14 +12,14 @@ import time from subprocess import CalledProcessError, DEVNULL -from wk.cfg.main import KIT_NAME_FULL +from wk.cfg.main import KIT_NAME_FULL, KIT_NAME_SHORT from wk.exe import ( get_procs, run_program, popen_program, wait_for_procs, ) -from wk.io import delete_folder, rename_item +from wk.io import delete_folder, get_path_obj, rename_item from wk.kit.tools import ( ARCH, download_tool, @@ -42,6 +42,7 @@ from wk.std import ( GenericWarning, Menu, TryAndPrint, + abort, ask, clear_screen, color_string, @@ -60,6 +61,10 @@ from wk.std import ( LOG = logging.getLogger(__name__) AUTO_REPAIR_DELAY_IN_SECONDS = 30 AUTO_REPAIR_KEY = fr'Software\{KIT_NAME_FULL}\Auto Repairs' +BACKUP_BROWSER_BASE_CMD = ( + get_tool_path('7-Zip', '7za'), + 'a', '-t7z', '-mx=1', '-bso0', '-bse0', '-bsp0', + ) BLEACH_BIT_CLEANERS = ( # Applications 'adobe_reader.cache', @@ -400,7 +405,10 @@ def run_auto_repairs(base_menus): for group, menu in menus.items(): if group in ('Main', 'Options'): continue - run_group(group, menu) + try: + run_group(group, menu) + except KeyboardInterrupt: + abort() # Done end_session() @@ -567,6 +575,12 @@ def auto_adwcleaner(group, name): save_settings(group, name, result=result) +def auto_backup_browser_profiles(group, name): + """Backup browser profiles.""" + backup_all_browser_profiles(use_try_print=True) + save_settings(group, name, done=True, failed=False, message='DONE') + + def auto_backup_power_plans(group, name): """Backup power plans.""" result = TRY_PRINT.run('Backup Power Plans...', export_power_plans) @@ -796,13 +810,89 @@ def set_backup_path(name, date=False): def set_local_storage_path(folder, name, date=False): """Get path for local storage, returns pathlib.Path.""" - local_path = format_log_path(log_name=f'../{folder}/{name}').with_suffix('') + local_path = get_path_obj(f'{SYSTEMDRIVE}/{KIT_NAME_SHORT}/{folder}/{name}') if date: local_path = local_path.joinpath(time.strftime('%Y-%m-%d')) - return local_path.resolve() + return local_path + + +def set_quarantine_path(name, date=False): + """Set quarantine path, returns pathlib.Path.""" + return set_local_storage_path('Quarantine', name, date) # Tool Functions +def backup_all_browser_profiles(use_try_print=False): + """Backup browser profiles for all users.""" + users = get_path_obj(f'{SYSTEMDRIVE}/Users') + for userprofile in users.iterdir(): + if use_try_print: + print_info(f'{" "*6}{userprofile.name}') + backup_browser_profiles(userprofile, use_try_print) + + +def backup_browser_chromium(backup_path, browser, search_path, use_try_print): + """Backup Chromium-based browser profile.""" + for item in search_path.iterdir(): + match = re.match(r'^(Default|Profile).*', item.name, re.IGNORECASE) + if not match: + continue + output_path = backup_path.joinpath(f'{browser}-{item.name}.7z') + cmd = [ + *BACKUP_BROWSER_BASE_CMD, + output_path, item.joinpath('*'), '-x!*Cache*', '-x!Service Worker', + ] + if use_try_print: + TRY_PRINT.run( + f'{" "*8}{browser} ({item.name})...', + run_program, cmd, check=False, + ) + else: + run_program(cmd, check=False) + + +def backup_browser_firefox(backup_path, search_path, use_try_print): + """Backup Firefox browser profile.""" + output_path = backup_path.joinpath('Firefox.7z') + cmd = [ + *BACKUP_BROWSER_BASE_CMD, output_path, + search_path.joinpath('Profiles'), search_path.joinpath('profiles.ini'), + ] + if use_try_print: + TRY_PRINT.run(f'{" "*8}Firefox (All)...', run_program, cmd, check=False) + else: + run_program(cmd, check=False) + + +def backup_browser_profiles(userprofile, use_try_print=False): + """Backup browser profiles for userprofile.""" + backup_path = set_backup_path('Browsers', date=True) + backup_path = backup_path.joinpath(userprofile.name) + backup_path.mkdir(parents=True, exist_ok=True) + + # Chrome + search_path = userprofile.joinpath('AppData/Local/Google/Chrome/User Data') + if search_path.exists(): + backup_browser_chromium(backup_path, 'Chrome', search_path, use_try_print) + + # Edge + search_path = userprofile.joinpath('AppData/Local/Microsoft/Edge/User Data') + if search_path.exists(): + backup_browser_chromium(backup_path, 'Edge', search_path, use_try_print) + + # Firefox + search_path = userprofile.joinpath('AppData/Roaming/Mozilla/Firefox') + if search_path.joinpath('Profiles').exists(): + backup_browser_firefox(backup_path, search_path, use_try_print) + + # Remove empty folders + try: + backup_path.rmdir() + except OSError: + # Only looking for empty folders + pass + + def backup_registry(): """Backup Registry.""" backup_path = set_backup_path('Registry', date=True) @@ -905,9 +995,7 @@ def run_kvrt(): """Run KVRT scan.""" log_path = format_log_path(log_name='KVRT', timestamp=True, tool=True) log_path.parent.mkdir(parents=True, exist_ok=True) - quarantine_path = set_local_storage_path( - 'Quarantine', 'KVRT', date=True, - ) + quarantine_path = set_quarantine_path('KVRT') quarantine_path.mkdir(parents=True, exist_ok=True) cmd_args = ( '-accepteula', @@ -996,9 +1084,7 @@ def run_tdsskiller(): """Run TDSSKiller scan.""" log_path = format_log_path(log_name='TDSSKiller', timestamp=True, tool=True) log_path.parent.mkdir(parents=True, exist_ok=True) - quarantine_path = set_local_storage_path( - 'Quarantine', 'TDSSKiller', date=True, - ) + quarantine_path = set_quarantine_path('TDSSKiller') quarantine_path.mkdir(parents=True, exist_ok=True) cmd_args = ( '-accepteula',