def test_MetadataSyncJob_success_with_missing_key(mocker, homedir, session, session_maker): """ Check that we can gracefully handle missing source keys. """ gpg = GpgHelper(homedir, session_maker, is_qubes=False) job = MetadataSyncJob(homedir, gpg) mock_source = factory.RemoteSource(key={ 'type': 'PGP', 'public': '', 'fingerprint': '', }) mock_key_import = mocker.patch.object(job.gpg, 'import_key') mock_get_remote_data = mocker.patch( 'securedrop_client.api_jobs.sync.get_remote_data', return_value=([mock_source], [], [])) api_client = mocker.MagicMock() api_client.default_request_timeout = mocker.MagicMock() job.call_api(api_client, session) assert mock_key_import.call_count == 0 assert mock_get_remote_data.call_count == 1
def __init__( self, api_client: API, session_maker: scoped_session, gpg: GpgHelper, data_dir: str, sync_started: pyqtSignal, on_sync_success, on_sync_failure, ): super().__init__() self.api_client = api_client self.session_maker = session_maker self.gpg = gpg self.data_dir = data_dir self.sync_started = sync_started self.on_sync_success = on_sync_success self.on_sync_failure = on_sync_failure self.job = MetadataSyncJob(self.data_dir) self.job.success_signal.connect(self.on_sync_success, type=Qt.QueuedConnection) self.job.failure_signal.connect(self.on_sync_failure, type=Qt.QueuedConnection)
def test_MetadataSyncJob_success_with_key_import_fail(mocker, homedir, session, session_maker): """ Check that we can gracefully handle a key import failure. """ gpg = GpgHelper(homedir, session_maker, is_qubes=False) job = MetadataSyncJob(homedir, gpg) mock_source = factory.RemoteSource(key={ 'type': 'PGP', 'public': PUB_KEY, 'fingerprint': '123456ABC', }) mock_key_import = mocker.patch.object(job.gpg, 'import_key', side_effect=CryptoError) mock_get_remote_data = mocker.patch( 'securedrop_client.api_jobs.sync.get_remote_data', return_value=([mock_source], [], [])) api_client = mocker.MagicMock() api_client.default_request_timeout = mocker.MagicMock() job.call_api(api_client, session) assert mock_key_import.call_args[0][0] == mock_source.uuid assert mock_key_import.call_args[0][1] == mock_source.key['public'] assert mock_key_import.call_args[0][2] == mock_source.key['fingerprint'] assert mock_get_remote_data.call_count == 1
class ApiSyncBackgroundTask(QObject): """ ApiSyncBackgroundTask provides a sync method that executes a MetadataSyncJob. """ def __init__( self, api_client: API, session_maker: scoped_session, gpg: GpgHelper, data_dir: str, sync_started: pyqtSignal, on_sync_success, on_sync_failure, ): super().__init__() self.api_client = api_client self.session_maker = session_maker self.gpg = gpg self.data_dir = data_dir self.sync_started = sync_started self.on_sync_success = on_sync_success self.on_sync_failure = on_sync_failure self.job = MetadataSyncJob(self.data_dir) self.job.success_signal.connect(self.on_sync_success, type=Qt.QueuedConnection) self.job.failure_signal.connect(self.on_sync_failure, type=Qt.QueuedConnection) def sync(self) -> None: """ Create and run a new MetadataSyncJob. """ try: self.sync_started.emit() session = self.session_maker() self.job.remaining_attempts = 2 self.job._do_call_api(self.api_client, session) except ApiInaccessibleError as e: self.job.failure_signal.emit( e) # the job's failure signal is not emitted in base except Exception: pass # the job's failure signal is emitted for everything else in base finally: session.close()
def test_MetadataSyncJob_success(mocker, homedir, session, session_maker): job = MetadataSyncJob(homedir) mock_source = factory.RemoteSource(key={ "type": "PGP", "public": PUB_KEY, "fingerprint": "123456ABC" }) mock_get_remote_data = mocker.patch( "securedrop_client.api_jobs.sync.get_remote_data", return_value=([mock_source], [], [])) api_client = mocker.MagicMock() api_client.default_request_timeout = mocker.MagicMock() api_client.default_request_timeout = mocker.MagicMock() job.call_api(api_client, session) assert mock_get_remote_data.call_count == 1
def test_MetadataSyncJob_success_with_missing_key(mocker, homedir, session, session_maker): """ Check that we can gracefully handle missing source keys. """ job = MetadataSyncJob(homedir) mock_source = factory.RemoteSource(key={ "type": "PGP", "public": "", "fingerprint": "" }) mock_get_remote_data = mocker.patch( "securedrop_client.api_jobs.sync.get_remote_data", return_value=([mock_source], [], [])) api_client = mocker.MagicMock() api_client.default_request_timeout = mocker.MagicMock() job.call_api(api_client, session) assert mock_get_remote_data.call_count == 1
def test_MetadataSyncJob_only_import_new_source_keys(mocker, homedir, session, session_maker): """ Verify that we only import source keys we don't already have. """ gpg = GpgHelper(homedir, session_maker, is_qubes=False) job = MetadataSyncJob(homedir, gpg) mock_source = factory.RemoteSource(key={ 'type': 'PGP', 'public': PUB_KEY, 'fingerprint': '123456ABC', }) mock_get_remote_data = mocker.patch( 'securedrop_client.api_jobs.sync.get_remote_data', return_value=([mock_source], [], [])) api_client = mocker.MagicMock() api_client.default_request_timeout = mocker.MagicMock() crypto_logger = mocker.patch('securedrop_client.crypto.logger') storage_logger = mocker.patch('securedrop_client.storage.logger') job.call_api(api_client, session) assert mock_get_remote_data.call_count == 1 log_msg = crypto_logger.debug.call_args_list[0][0] assert log_msg == ('Importing key with fingerprint %s', mock_source.key['fingerprint']) job.call_api(api_client, session) assert mock_get_remote_data.call_count == 2 log_msg = storage_logger.debug.call_args_list[1][0][0] assert log_msg == 'Source key data is unchanged'