async def restore_complete_doit(fname_or_fd, words): from main import dis # build password password = '******'.join(words) # filename already picked, taste it and maybe consider using it's data. try: fd = open(fname_or_fd, 'rb') if isinstance(fname_or_fd, str) else fname_or_fd except: await ux_show_story('Unable to open backup file. \n\n' + str(fname_or_fd)) return try: if not words: contents = fd.read() else: try: compat7z.check_file_headers(fd) except Exception as e: await ux_show_story('Unable to read backup file. Has it been touched?' '\n\nError: ' + str(e)) return dis.fullscreen("Decrypting...") try: zz = compat7z.Builder() fname, contents = zz.read_file(fd, password, progress_fcn=dis.progress_bar_show) assert fname == 'ckcc-backup.txt', "Wrong filename in archive" # simple quick sanity check assert contents[0:1] == b'#' and contents[-1:] == b'\n', "Corrupted after decrypt" except Exception as e: # assume everything here is "password wrong" errors print("pw wrong? %s" % e) await ux_show_story('Unable to decrypt backup file. Incorrect password?' '\n\nTried:\n\n' + password) return finally: fd.close() vals = {} for line in contents.decode().split('\n'): if not line: continue if line[0] == '#': continue try: k,v = line.split(' = ', 1) #print("%s = %s" % (k, v)) vals[k] = ujson.loads(v) except: print("unable to decode line: %r" % line) # but keep going! await restore_from_dict(vals)
async def verify_backup_file(fname_or_fd): # read 7z header, and measure checksums # - no password is wanted/required # - really just checking CRC32, but that's enough against truncated files from files import CardSlot, CardMissingError from actions import needs_microsd prob = None fd = None # filename already picked, open it. try: with CardSlot() as card: prob = 'Unable to open backup file.' fd = open(fname_or_fd, 'rb') if isinstance(fname_or_fd, str) else fname_or_fd prob = 'Unable to read backup file headers. Might be truncated.' compat7z.check_file_headers(fd) prob = 'Unable to verify backup file contents.' zz = compat7z.Builder() files = zz.verify_file_crc(fd, MAX_BACKUP_FILE_SIZE) assert len(files) == 1 fname, fsize = files[0] assert fname == 'ckcc-backup.txt' assert 400 < fsize < MAX_BACKUP_FILE_SIZE, 'size' except CardMissingError: await needs_microsd() return except Exception as e: await ux_show_story(prob + '\n\nError: ' + str(e)) return finally: if fd: fd.close() await ux_show_story( "Backup file CRC checks out okay.\n\nPlease note this is only a check against accidental truncation and similar. Targeted modifications can still pass this test." )
async def restore_complete_doit(fname_or_fd, words): # Open file, read it, maybe decrypt it; return string if any error # - some errors will be shown, None return in that case # - no return if successful (due to reboot) from main import dis from files import CardSlot, CardMissingError from actions import needs_microsd # build password password = '******'.join(words) prob = None try: with CardSlot() as card: # filename already picked, taste it and maybe consider using its data. try: fd = open(fname_or_fd, 'rb') if isinstance( fname_or_fd, str) else fname_or_fd except: return 'Unable to open backup file.\n\n' + str(fname_or_fd) try: if not words: contents = fd.read() else: try: compat7z.check_file_headers(fd) except Exception as e: return 'Unable to read backup file. Has it been touched?\n\nError: ' \ + str(e) dis.fullscreen("Decrypting...") try: zz = compat7z.Builder() fname, contents = zz.read_file( fd, password, MAX_BACKUP_FILE_SIZE, progress_fcn=dis.progress_bar_show) # simple quick sanity checks assert fname == 'ckcc-backup.txt' assert contents[0:1] == b'#' and contents[-1:] == b'\n' except Exception as e: # assume everything here is "password wrong" errors #print("pw wrong? %s" % e) return ( 'Unable to decrypt backup file. Incorrect password?' '\n\nTried:\n\n' + password) finally: fd.close() except CardMissingError: await needs_microsd() return vals = {} for line in contents.decode().split('\n'): if not line: continue if line[0] == '#': continue try: k, v = line.split(' = ', 1) #print("%s = %s" % (k, v)) vals[k] = ujson.loads(v) except: print("unable to decode line: %r" % line) # but keep going! # this leads to reboot if it works, else errors shown, etc. return await restore_from_dict(vals)