def _verify_installed_binary(self): # Verifies latest downloaded archive against known hash log.debug('Checking for current installed binary to patch') status = True with ChDir(self.update_folder): if not os.path.exists(self.current_filename): log.debug('Cannot find archive to patch') status = False else: installed_file_hash = get_package_hashes(self.current_filename) if self.current_file_hash != installed_file_hash: log.debug('Binary hash mismatch') status = False else: # Read binary into memory to begin patching try: with open(self.current_filename, 'rb') as f: self.og_binary = f.read() except FileNotFoundError: status = False log.debug("Current archive missing") except Exception as err: status = False log.debug(err, exc_info=True) if status: log.debug('Binary found and verified') return status
def test_package_hash(): with io.open('hash-test.txt', 'w', encoding='utf-8') as f: f.write('I should find some lorem text' * 123) digest = ('cb44ec613a594f3b20e46b768c5ee780e0a9b66ac' '6d5ac1468ca4d3635c4aa9b') assert digest == get_package_hashes('hash-test.txt')
def _write_update_to_disk(self): # pragma: no cover # Writes updated binary to disk log.debug("Writing update to disk") filename_key = "{}*{}*{}*{}*{}".format( settings.UPDATES_KEY, self.name, self.latest_version, self.platform, "filename", ) filename = self.star_access_update_data.get(filename_key) if filename is None: raise PatcherError("Filename missing in version file") with ChDir(self.update_folder): try: with open(filename, "wb") as f: f.write(self.og_binary) log.debug("Wrote update file") except IOError: # Removes file if it got created if os.path.exists(filename): remove_any(filename) log.debug("Failed to open file for writing") raise PatcherError("Failed to open file for writing") else: file_info = self._get_info(self.name, self.latest_version, option="file") new_file_hash = file_info["file_hash"] log.debug("checking file hash match") if new_file_hash != get_package_hashes(filename): log.debug("Version file hash: %s", new_file_hash) log.debug("Actual file hash: %s", get_package_hashes(filename)) log.debug("File hash does not match") remove_any(filename) raise PatcherError("Bad hash on patched file", expected=True)
def _write_update_to_disk(self): # pragma: no cover # Writes updated binary to disk log.debug('Writing update to disk') filename_key = '{}*{}*{}*{}*{}'.format(settings.UPDATES_KEY, self.name, self.latest_version, self.platform, 'filename') filename = self.star_access_update_data.get(filename_key) if filename is None: raise PatcherError('Filename missing in version file') with ChDir(self.update_folder): try: with open(filename, 'wb') as f: f.write(self.og_binary) log.debug('Wrote update file') except IOError: # Removes file if it got created if os.path.exists(filename): remove_any(filename) log.debug('Failed to open file for writing') raise PatcherError('Failed to open file for writing') else: file_info = self._get_info(self.name, self.latest_version, option='file') new_file_hash = file_info['file_hash'] log.debug('checking file hash match') if new_file_hash != get_package_hashes(filename): log.debug('Version file hash: %s', new_file_hash) log.debug('Actual file hash: %s', get_package_hashes(filename)) log.debug('File hash does not match') remove_any(filename) raise PatcherError('Bad hash on patched file', expected=True)
def _verify_installed_binary(self): # Verifies latest downloaded archive against known hash log.debug('Checking for current installed binary to patch') status = True with dsdev_utils.paths.ChDir(self.update_folder): if not os.path.exists(self.current_filename): log.debug('Cannot find archive to patch') status = False else: installed_file_hash = get_package_hashes(self.current_filename) if self.current_file_hash != installed_file_hash: log.debug('Binary hash mismatch') status = False else: # Read binary into memory to begin patching with open(self.current_filename, 'rb') as f: self.og_binary = f.read() if status: log.debug('Binary found and verified') return status
def setUp(self): # pylint: disable=too-many-statements # pylint: disable=too-many-locals self.initialWorkingDir = os.getcwd() userDataDir = appdirs.user_data_dir(APP_NAME, COMPANY_NAME) if os.path.exists(userDataDir): shutil.rmtree(userDataDir) os.makedirs(userDataDir) versionsUserDataFilePath = os.path.join(userDataDir, 'versions.gz') userDataUpdateDir = os.path.join(userDataDir, "update") os.mkdir(userDataUpdateDir) system = get_system() self.currentFilename = \ VERSIONS['updates'][APP_NAME][CURRENT_VERSION_PYU_FORMAT]\ [system]['filename'] currentFilePath = os.path.join(userDataUpdateDir, self.currentFilename) with open(currentFilePath, "wb") as currentFile: currentFile.write("%s" % CURRENT_VERSION) currentFile.seek(FILE_SIZE - 1) currentFile.write("\0") fileHash = get_package_hashes(currentFilePath) VERSIONS['updates'][APP_NAME][CURRENT_VERSION_PYU_FORMAT]\ [system]['file_hash'] = fileHash tempFile = tempfile.NamedTemporaryFile() self.fileServerDir = tempFile.name tempFile.close() os.mkdir(self.fileServerDir) os.chdir(self.fileServerDir) self.updateFilename = \ VERSIONS['updates'][APP_NAME][UPDATE_VERSION_PYU_FORMAT]\ [system]['filename'] with open(self.updateFilename, "wb") as updateFile: updateFile.write("%s" % UPDATE_VERSION) updateFile.seek(FILE_SIZE - 1) updateFile.write("\0") os.chdir(self.fileServerDir) fileHash = get_package_hashes(self.updateFilename) VERSIONS['updates'][APP_NAME][UPDATE_VERSION_PYU_FORMAT]\ [system]['file_hash'] = fileHash self.patchFilename = \ VERSIONS['updates'][APP_NAME][UPDATE_VERSION_PYU_FORMAT]\ [system]['patch_name'] bsdiff4.file_diff(currentFilePath, self.updateFilename, self.patchFilename) os.chdir(self.fileServerDir) fileHash = get_package_hashes(self.patchFilename) VERSIONS['updates'][APP_NAME][UPDATE_VERSION_PYU_FORMAT]\ [system]['patch_hash'] = fileHash os.chdir(self.initialWorkingDir) privateKey = ed25519.SigningKey(PRIVATE_KEY.encode('utf-8'), encoding='base64') signature = privateKey.sign(six.b(json.dumps(VERSIONS, sort_keys=True)), encoding='base64').decode() VERSIONS['signature'] = signature keysFilePath = os.path.join(self.fileServerDir, 'keys.gz') with gzip.open(keysFilePath, 'wb') as keysFile: keysFile.write(json.dumps(KEYS, sort_keys=True)) versionsFilePath = os.path.join(self.fileServerDir, 'versions.gz') with gzip.open(versionsFilePath, 'wb') as versionsFile: versionsFile.write(json.dumps(VERSIONS, sort_keys=True)) with gzip.open(versionsUserDataFilePath, 'wb') as versionsFile: versionsFile.write(json.dumps(VERSIONS, sort_keys=True)) tempFile = tempfile.NamedTemporaryFile() self.tempDir = tempFile.name tempFile.close() settings.CONFIG_DATA_FOLDER = os.path.join(self.tempDir, '.pyupdater') settings.USER_DATA_FOLDER = os.path.join(self.tempDir, 'pyu-data') os.mkdir(self.tempDir) os.mkdir(settings.USER_DATA_FOLDER) os.mkdir(settings.CONFIG_DATA_FOLDER) # The way we set the App name below avoids having to # create .pyupdater/config.pyu: settings.GENERIC_APP_NAME = APP_NAME settings.GENERIC_COMPANY_NAME = COMPANY_NAME os.environ['PYUPDATER_FILESERVER_DIR'] = self.fileServerDir os.environ['WXUPDATEDEMO_TESTING'] = 'True' os.environ['WXUPDATEDEMO_TESTING_FROZEN'] = 'True' os.environ['WXUPDATEDEMO_TESTING_APP_NAME'] = APP_NAME os.environ['WXUPDATEDEMO_TESTING_COMPANY_NAME'] = COMPANY_NAME os.environ['WXUPDATEDEMO_TESTING_APP_VERSION'] = CURRENT_VERSION os.environ['WXUPDATEDEMO_TESTING_PUBLIC_KEY'] = PUBLIC_KEY