Esempio n. 1
0
def test_FileDownloadJob_happy_path_unknown_etag(mocker, homedir, session,
                                                 session_maker):
    source = factory.Source()
    file_ = factory.File(source=source, is_downloaded=None, is_decrypted=None)
    session.add(source)
    session.add(file_)
    session.commit()

    gpg = GpgHelper(homedir, session_maker, is_qubes=False)

    def fake_download(sdk_obj: SdkSubmission, timeout: int) -> Tuple[str, str]:
        """
        :return: (etag, path_to_dl)
        """
        full_path = os.path.join(homedir, "data", "mock")
        with open(full_path, "wb") as f:
            f.write(b"")
        return ("UNKNOWN:abc123", full_path)

    api_client = mocker.MagicMock()
    api_client.default_request_timeout = mocker.MagicMock()
    api_client.download_submission = fake_download

    job = FileDownloadJob(file_.uuid, os.path.join(homedir, "data"), gpg)

    mock_decrypt = patch_decrypt(mocker, homedir, gpg, file_.filename)
    mock_logger = mocker.patch("securedrop_client.api_jobs.downloads.logger")

    job.call_api(api_client, session)

    log_msg = mock_logger.debug.call_args_list[0][0][0]
    assert log_msg.startswith("Unknown hash algorithm")

    # ensure mocks aren't stale
    assert mock_decrypt.called
Esempio n. 2
0
def test_FileDownloadJob_bad_sha256_etag(mocker, homedir, session,
                                         session_maker):
    source = factory.Source()
    file_ = factory.File(source=source, is_downloaded=None, is_decrypted=None)
    session.add(source)
    session.add(file_)
    session.commit()

    gpg = GpgHelper(homedir, session_maker, is_qubes=False)

    def fake_download(sdk_obj: SdkSubmission, timeout: int) -> Tuple[str, str]:
        '''
        :return: (etag, path_to_dl)
        '''
        full_path = os.path.join(homedir, 'data', 'mock')
        with open(full_path, 'wb') as f:
            f.write(b'')

        return ('sha256:not-a-sha-sum', full_path)

    api_client = mocker.MagicMock()
    api_client.default_request_timeout = mocker.MagicMock()
    api_client.download_submission = fake_download

    job = FileDownloadJob(
        file_.uuid,
        os.path.join(homedir, 'data'),
        gpg,
    )

    with pytest.raises(DownloadChecksumMismatchException):
        job.call_api(api_client, session)
Esempio n. 3
0
def main_window_no_key(mocker, homedir):
    # Setup
    app = QApplication([])
    gui = Window()
    app.setActiveWindow(gui)
    gui.show()
    controller = Controller("http://localhost", gui, mocker.MagicMock(), homedir, proxy=False)
    controller.qubes = False
    gui.setup(controller)

    # Create a source widget
    source_list = gui.main_view.source_list
    source = factory.Source(public_key=None)
    source_list.update([source])

    # Create a file widget, message widget, and reply widget
    mocker.patch("securedrop_client.gui.widgets.humanize_filesize", return_value="100")
    mocker.patch(
        "securedrop_client.gui.SecureQLabel.get_elided_text", return_value="1-yellow-doc.gz.gpg"
    )
    source.collection.append(
        [
            factory.File(source=source, filename="1-yellow-doc.gz.gpg"),
            factory.Message(source=source, filename="2-yellow-msg.gpg"),
            factory.Reply(source=source, filename="3-yellow-reply.gpg"),
        ]
    )
    source_list.setCurrentItem(source_list.item(0))
    gui.main_view.on_source_changed()

    yield gui

    # Teardown
    gui.login_dialog.close()
    app.exit()
Esempio n. 4
0
def test_mark_file_as_downloaded(mocker):
    session = mocker.MagicMock()
    file = factory.File(source=factory.Source(), is_downloaded=False)
    session.query().filter_by().one.return_value = file
    mark_as_downloaded(type(file), "mock_uuid", session)
    assert file.is_downloaded is True
    session.add.assert_called_once_with(file)
    session.commit.assert_called_once_with()
Esempio n. 5
0
def test_get_file(mocker, session):
    source = factory.Source()
    file = factory.File(source=source)
    session.add(source)
    session.add(file)

    result = get_file(session, file.uuid)

    assert result == file
Esempio n. 6
0
def test_file_with_download_error(session, download_error_codes):
    f = factory.File()
    download_error = (session.query(DownloadError).filter_by(
        name=DownloadErrorCodes.CHECKSUM_ERROR.name).one())
    f.download_error = download_error
    session.commit()

    classname = f.__class__.__name__.lower()
    assert str(f) == f"cannot download {classname}"
Esempio n. 7
0
def test_set_file_decryption_status_with_content_null_to_false(
        mocker, session):
    file = factory.File(source=factory.Source(), is_decrypted=None)
    session.add(file)
    session.commit()

    mark_as_decrypted(type(file), file.uuid, session, False)

    assert file.is_decrypted is False
Esempio n. 8
0
def test_set_file_decryption_status_with_content_false_to_true(
        mocker, session):
    file = factory.File(source=factory.Source(),
                        is_downloaded=True,
                        is_decrypted=False)
    session.add(file)
    session.commit()

    mark_as_decrypted(type(file), file.uuid, session)

    assert file.is_decrypted is True
Esempio n. 9
0
def test_timeout_length_of_file_downloads(mocker, homedir, session,
                                          session_maker):
    """
    Ensure that files downloads have timeouts scaled by the size of the file.
    """
    source = factory.Source()
    small_file = factory.File(source=source,
                              is_downloaded=None,
                              is_decrypted=None,
                              size=1)
    large_file = factory.File(source=source,
                              is_downloaded=None,
                              is_decrypted=None,
                              size=100)
    session.add(source)
    session.add(small_file)
    session.add(large_file)
    session.commit()

    gpg = GpgHelper(homedir, session_maker, is_qubes=False)

    small_job = FileDownloadJob(
        small_file.uuid,
        os.path.join(homedir, 'data'),
        gpg,
    )
    large_job = FileDownloadJob(
        small_file.uuid,
        os.path.join(homedir, 'data'),
        gpg,
    )

    small_file_timeout = small_job._get_realistic_timeout(small_file.size)
    large_file_timeout = large_job._get_realistic_timeout(large_file.size)

    assert small_file_timeout < large_file_timeout
Esempio n. 10
0
def test_update_file_size(homedir, session):
    source = factory.Source()
    f = factory.File(source=source)
    session.add(f)
    session.commit()

    real_size = 2112
    data_dir = os.path.join(homedir, "data")
    file_location = f.location(data_dir)

    os.makedirs(os.path.dirname(file_location), mode=0o700, exist_ok=True)
    with open(file_location, mode="w") as f1:
        f1.write("x" * real_size)
    update_file_size(f.uuid, data_dir, session)

    assert f.size == real_size
Esempio n. 11
0
def test_FileDownloadJob_decryption_error(mocker, homedir, session,
                                          session_maker):
    source = factory.Source()
    file_ = factory.File(source=source, is_downloaded=None, is_decrypted=None)
    session.add(source)
    session.add(file_)
    session.commit()

    gpg = GpgHelper(homedir, session_maker, is_qubes=False)
    mock_decrypt = mocker.patch.object(gpg,
                                       'decrypt_submission_or_reply',
                                       side_effect=CryptoError)

    def fake_download(sdk_obj: SdkSubmission, timeout: int) -> Tuple[str, str]:
        '''
        :return: (etag, path_to_dl)
        '''
        full_path = os.path.join(homedir, 'data', 'mock')
        with open(full_path, 'wb') as f:
            f.write(b'wat')

        # sha256 of b'wat'
        return (
            'sha256:f00a787f7492a95e165b470702f4fe9373583fbdc025b2c8bdf0262cc48fcff4',
            full_path)

    api_client = mocker.MagicMock()
    api_client.default_request_timeout = mocker.MagicMock()
    api_client.download_submission = fake_download

    job = FileDownloadJob(
        file_.uuid,
        os.path.join(homedir, 'data'),
        gpg,
    )

    mock_logger = mocker.patch('securedrop_client.api_jobs.downloads.logger')

    with pytest.raises(DownloadDecryptionException):
        job.call_api(api_client, session)

    log_msg = mock_logger.debug.call_args_list[0][0][0]
    assert log_msg.startswith('Failed to decrypt file')

    # ensure mocks aren't stale
    assert mock_decrypt.called
Esempio n. 12
0
def test_FileDownloadJob_message_already_decrypted(mocker, homedir, session,
                                                   session_maker):
    """
    Test that call_api just returns uuid if already decrypted.
    """
    file_ = factory.File(source=factory.Source(),
                         is_downloaded=True,
                         is_decrypted=True)
    session.add(file_)
    session.commit()
    gpg = GpgHelper(homedir, session_maker, is_qubes=False)
    job = FileDownloadJob(file_.uuid, homedir, gpg)
    decrypt_fn = mocker.patch.object(job.gpg, 'decrypt_submission_or_reply')
    api_client = mocker.MagicMock()
    download_fn = mocker.patch.object(api_client, 'download_submission')

    return_uuid = job.call_api(api_client, session)

    assert file_.uuid == return_uuid
    decrypt_fn.assert_not_called()
    download_fn.assert_not_called()
Esempio n. 13
0
def test_FileDownloadJob_message_already_downloaded(mocker, homedir, session,
                                                    session_maker):
    """
    Test that call_api just decrypts and returns uuid if already downloaded.
    """
    file_ = factory.File(source=factory.Source(),
                         is_downloaded=True,
                         is_decrypted=False)
    session.add(file_)
    session.commit()
    gpg = GpgHelper(homedir, session_maker, is_qubes=False)
    job = FileDownloadJob(file_.uuid, os.path.join(homedir, 'data'), gpg)
    patch_decrypt(mocker, homedir, gpg, file_.filename)
    api_client = mocker.MagicMock()
    download_fn = mocker.patch.object(api_client, 'download_submission')

    return_uuid = job.call_api(api_client, session)

    assert file_.uuid == return_uuid
    assert file_.is_decrypted is True
    download_fn.assert_not_called()
Esempio n. 14
0
def test_FileDownloadJob_happy_path_no_etag(mocker, homedir, session,
                                            session_maker):
    source = factory.Source()
    file_ = factory.File(source=source, is_downloaded=False, is_decrypted=None)
    session.add(source)
    session.add(file_)
    session.commit()

    gpg = GpgHelper(homedir, session_maker, is_qubes=False)
    mock_decrypt = patch_decrypt(mocker, homedir, gpg, file_.filename)

    def fake_download(sdk_obj: SdkSubmission, timeout: int) -> Tuple[str, str]:
        '''
        :return: (etag, path_to_dl)
        '''
        full_path = os.path.join(homedir, 'data', 'mock')
        with open(full_path, 'wb') as f:
            f.write(b'')
        return ('', full_path)

    api_client = mocker.MagicMock()
    api_client.default_request_timeout = mocker.MagicMock()
    api_client.download_submission = fake_download

    job = FileDownloadJob(
        file_.uuid,
        os.path.join(homedir, 'data'),
        gpg,
    )

    mock_logger = mocker.patch('securedrop_client.api_jobs.downloads.logger')

    job.call_api(api_client, session)

    log_msg = mock_logger.debug.call_args_list[0][0][0]
    assert log_msg.startswith('No ETag. Skipping integrity check')

    # ensure mocks aren't stale
    assert mock_decrypt.called
Esempio n. 15
0
def test_FileDownloadJob_happy_path_sha256_etag(mocker, homedir, session,
                                                session_maker):
    source = factory.Source()
    file_ = factory.File(source=source, is_downloaded=None, is_decrypted=None)
    session.add(source)
    session.add(file_)
    session.commit()

    gpg = GpgHelper(homedir, session_maker, is_qubes=False)
    mock_decrypt = patch_decrypt(mocker, homedir, gpg, file_.filename)

    def fake_download(sdk_obj: SdkSubmission, timeout: int) -> Tuple[str, str]:
        '''
        :return: (etag, path_to_dl)
        '''
        full_path = os.path.join(homedir, 'data', 'mock')
        with open(full_path, 'wb') as f:
            f.write(b'wat')

        # sha256 of b'wat'
        return (
            'sha256:f00a787f7492a95e165b470702f4fe9373583fbdc025b2c8bdf0262cc48fcff4',
            full_path)

    api_client = mocker.MagicMock()
    api_client.default_request_timeout = mocker.MagicMock()
    api_client.download_submission = fake_download

    job = FileDownloadJob(
        file_.uuid,
        os.path.join(homedir, 'data'),
        gpg,
    )

    job.call_api(api_client, session)

    # ensure mocks aren't stale
    assert mock_decrypt.called
Esempio n. 16
0
def test_FileDownloadJob_decryption_error(mocker, homedir, session,
                                          session_maker, download_error_codes):
    source = factory.Source()
    file_ = factory.File(source=source, is_downloaded=None, is_decrypted=None)
    session.add(source)
    session.add(file_)
    session.commit()

    gpg = GpgHelper(homedir, session_maker, is_qubes=False)
    mock_decrypt = mocker.patch.object(gpg,
                                       "decrypt_submission_or_reply",
                                       side_effect=CryptoError)

    def fake_download(sdk_obj: SdkSubmission, timeout: int) -> Tuple[str, str]:
        """
        :return: (etag, path_to_dl)
        """
        full_path = os.path.join(homedir, "data", "mock")
        with open(full_path, "wb") as f:
            f.write(b"wat")

        # sha256 of b'wat'
        return (
            "sha256:f00a787f7492a95e165b470702f4fe9373583fbdc025b2c8bdf0262cc48fcff4",
            full_path,
        )

    api_client = mocker.MagicMock()
    api_client.default_request_timeout = mocker.MagicMock()
    api_client.download_submission = fake_download

    job = FileDownloadJob(file_.uuid, os.path.join(homedir, "data"), gpg)

    with pytest.raises(DownloadDecryptionException):
        job.call_api(api_client, session)

    # ensure mocks aren't stale
    assert mock_decrypt.called
Esempio n. 17
0
def test_timeout_length_of_file_downloads(mocker, homedir, session,
                                          session_maker):
    """
    Ensure that files downloads have timeouts scaled by the size of the file.
    """
    source = factory.Source()
    zero_byte_file = factory.File(source=source,
                                  is_downloaded=None,
                                  is_decrypted=None,
                                  size=0)
    one_byte_file = factory.File(source=source,
                                 is_downloaded=None,
                                 is_decrypted=None,
                                 size=1)
    KB_file = factory.File(source=source,
                           is_downloaded=None,
                           is_decrypted=None,
                           size=1000)
    fifty_KB_file = factory.File(source=source,
                                 is_downloaded=None,
                                 is_decrypted=None,
                                 size=50000)
    half_MB_file = factory.File(source=source,
                                is_downloaded=None,
                                is_decrypted=None,
                                size=500000)
    MB_file = factory.File(source=source,
                           is_downloaded=None,
                           is_decrypted=None,
                           size=1000000)
    five_MB_file = factory.File(source=source,
                                is_downloaded=None,
                                is_decrypted=None,
                                size=5000000)
    haf_GB_file = factory.File(source=source,
                               is_downloaded=None,
                               is_decrypted=None,
                               size=500000000)
    GB_file = factory.File(source=source,
                           is_downloaded=None,
                           is_decrypted=None,
                           size=1000000000)
    session.add(source)
    session.add(zero_byte_file)
    session.add(one_byte_file)
    session.add(KB_file)
    session.add(fifty_KB_file)
    session.add(half_MB_file)
    session.add(MB_file)
    session.add(five_MB_file)
    session.add(haf_GB_file)
    session.add(GB_file)
    session.commit()

    gpg = GpgHelper(homedir, session_maker, is_qubes=False)
    zero_byte_file_job = FileDownloadJob(zero_byte_file.uuid,
                                         os.path.join(homedir, 'data'), gpg)
    one_byte_file_job = FileDownloadJob(one_byte_file.uuid,
                                        os.path.join(homedir, 'data'), gpg)
    KB_file_job = FileDownloadJob(KB_file.uuid, os.path.join(homedir, 'data'),
                                  gpg)
    fifty_KB_file_job = FileDownloadJob(fifty_KB_file.uuid,
                                        os.path.join(homedir, 'data'), gpg)
    half_MB_file_job = FileDownloadJob(half_MB_file.uuid,
                                       os.path.join(homedir, 'data'), gpg)
    MB_file_job = FileDownloadJob(MB_file.uuid, os.path.join(homedir, 'data'),
                                  gpg)
    five_MB_file_job = FileDownloadJob(five_MB_file.uuid,
                                       os.path.join(homedir, 'data'), gpg)
    half_GB_file_job = FileDownloadJob(haf_GB_file.uuid,
                                       os.path.join(homedir, 'data'), gpg)
    GB_file_job = FileDownloadJob(GB_file.uuid, os.path.join(homedir, 'data'),
                                  gpg)

    zero_byte_file_timeout = zero_byte_file_job._get_realistic_timeout(
        zero_byte_file.size)
    one_byte_file_timeout = one_byte_file_job._get_realistic_timeout(
        one_byte_file.size)
    KB_file_timeout = KB_file_job._get_realistic_timeout(KB_file.size)
    fifty_KB_file_timeout = fifty_KB_file_job._get_realistic_timeout(
        fifty_KB_file.size)
    half_MB_file_timeout = half_MB_file_job._get_realistic_timeout(
        half_MB_file.size)
    MB_file_timeout = MB_file_job._get_realistic_timeout(MB_file.size)
    five_MB_file_timeout = five_MB_file_job._get_realistic_timeout(
        five_MB_file.size)
    GB_file_timeout = GB_file_job._get_realistic_timeout(GB_file.size)
    half_GB_file_timeout = half_GB_file_job._get_realistic_timeout(
        haf_GB_file.size)

    # timeout = ceil((file_size/100000)*1.5)+25
    assert zero_byte_file_timeout == 25
    assert one_byte_file_timeout == 26
    assert KB_file_timeout == 26
    assert fifty_KB_file_timeout == 26
    assert half_MB_file_timeout == 33
    assert MB_file_timeout == 40
    assert five_MB_file_timeout == 100
    assert half_GB_file_timeout == 7525
    assert GB_file_timeout == 15025