def test_encrypt_source_file(self, setup_journalist_key_and_gpg_folder,
                                 tmp_path):
        # Given an encryption manager
        journalist_key_fingerprint, gpg_key_dir = setup_journalist_key_and_gpg_folder
        encryption_mgr = EncryptionManager(
            gpg_key_dir=gpg_key_dir,
            journalist_key_fingerprint=journalist_key_fingerprint)

        # And a file to be submitted by a source - we use this python file
        file_to_encrypt_path = Path(__file__)
        with file_to_encrypt_path.open() as file_to_encrypt:

            # When the source tries to encrypt the file
            # It succeeds
            encrypted_file_path = tmp_path / "file.gpg"
            encryption_mgr.encrypt_source_file(
                file_in=file_to_encrypt,
                encrypted_file_path_out=encrypted_file_path,
            )

            # And the output file contains the encrypted data
            encrypted_file = encrypted_file_path.read_bytes()
            assert encrypted_file

        # And the journalist is able to decrypt the file
        with import_journalist_private_key(encryption_mgr):
            decrypted_file = encryption_mgr._gpg.decrypt(encrypted_file).data
        assert decrypted_file.decode() == file_to_encrypt_path.read_text()

        # And the source or anyone else is NOT able to decrypt the file
        # For GPG 2.1+, a non-null passphrase _must_ be passed to decrypt()
        assert not encryption_mgr._gpg.decrypt(encrypted_file,
                                               passphrase="test 123").ok
    def test_encrypt_source_message(self, setup_journalist_key_and_gpg_folder,
                                    tmp_path):
        # Given an encryption manager
        journalist_key_fingerprint, gpg_key_dir = setup_journalist_key_and_gpg_folder
        encryption_mgr = EncryptionManager(
            gpg_key_dir=gpg_key_dir,
            journalist_key_fingerprint=journalist_key_fingerprint)

        # And a message to be submitted by a source
        message = "s3cr3t message"

        # When the source tries to encrypt the message
        # It succeeds
        encrypted_message_path = tmp_path / "message.gpg"
        encryption_mgr.encrypt_source_message(
            message_in=message,
            encrypted_message_path_out=encrypted_message_path)

        # And the output file contains the encrypted data
        encrypted_message = encrypted_message_path.read_bytes()
        assert encrypted_message

        # And the journalist is able to decrypt the message
        with import_journalist_private_key(encryption_mgr):
            decrypted_message = encryption_mgr._gpg.decrypt(
                encrypted_message).data
        assert decrypted_message.decode() == message

        # And the source or anyone else is NOT able to decrypt the message
        # For GPG 2.1+, a non-null passphrase _must_ be passed to decrypt()
        assert not encryption_mgr._gpg.decrypt(encrypted_message,
                                               passphrase="test 123").ok
async def save_notes(message):
    msg = message["text"].replace('/save', '', 1).strip()
    if len(msg) > 0:
        msg = EncryptionManager(message["from"]["id"]).encrypt_data(msg)

        db.save_notes(message["from"]["id"], msg,
                      datetime.now().strftime("%y-%m-%d %H:%M:%S"))
        await message.reply("Saved 👍")
    else:
        await message.reply("SEND SOMETHING TO SAVE! 😕")
    def test_get_source_public_key_wrong_id(
            self, setup_journalist_key_and_gpg_folder):
        # Given an encryption manager
        journalist_key_fingerprint, gpg_key_dir = setup_journalist_key_and_gpg_folder
        encryption_mgr = EncryptionManager(
            gpg_key_dir=gpg_key_dir,
            journalist_key_fingerprint=journalist_key_fingerprint)

        # When using the encryption manager to fetch a key for an invalid filesystem id
        # It fails
        with pytest.raises(GpgKeyNotFoundError):
            encryption_mgr.get_source_public_key("1234test")
    def test_delete_source_key_pair_on_journalist_key(
            self, setup_journalist_key_and_gpg_folder):
        # Given an encryption manager
        journalist_key_fingerprint, gpg_key_dir = setup_journalist_key_and_gpg_folder
        encryption_mgr = EncryptionManager(
            gpg_key_dir=gpg_key_dir,
            journalist_key_fingerprint=journalist_key_fingerprint)

        # When trying to delete the journalist key via the encryption manager
        # It fails
        with pytest.raises(GpgKeyNotFoundError):
            encryption_mgr.delete_source_key_pair(journalist_key_fingerprint)
async def get_saved_notes(message):

    data = db.get_notes(message["from"]["id"])

    if len(data) > 0:
        msg = '''Your saved notes 📖 are:'''
        enc = EncryptionManager(message["from"]["id"])
        for i in data:
            msg += "\n\n" + enc.decrypt_data(i[0])
        await message.reply(msg)
        del enc
    else:
        await message.reply("YOU HAVE NOT SAVED ANYTHING YET! 😕")
    def test_get_journalist_public_key(self,
                                       setup_journalist_key_and_gpg_folder):
        # Given an encryption manager
        journalist_key_fingerprint, gpg_key_dir = setup_journalist_key_and_gpg_folder
        encryption_mgr = EncryptionManager(
            gpg_key_dir=gpg_key_dir,
            journalist_key_fingerprint=journalist_key_fingerprint)

        # When using the encryption manager to fetch the journalist public key
        # It succeeds
        journalist_pub_key = encryption_mgr.get_journalist_public_key()
        assert journalist_pub_key
        assert journalist_pub_key.startswith(
            "-----BEGIN PGP PUBLIC KEY BLOCK----")
    def test_encrypt_fails(self, setup_journalist_key_and_gpg_folder,
                           tmp_path):
        # Given an encryption manager
        journalist_key_fingerprint, gpg_key_dir = setup_journalist_key_and_gpg_folder
        encryption_mgr = EncryptionManager(
            gpg_key_dir=gpg_key_dir,
            journalist_key_fingerprint=journalist_key_fingerprint)

        # When trying to encrypt some data without providing any recipient
        # It fails and the right exception is raised
        with pytest.raises(GpgEncryptError) as exc:
            encryption_mgr._encrypt(
                using_keys_with_fingerprints=[],
                plaintext_in="test",
                ciphertext_path_out=tmp_path / "encrypt_fails",
            )
        assert "no terminal at all requested" in str(exc)
    def test_generate_source_key_pair(self,
                                      setup_journalist_key_and_gpg_folder,
                                      source_app, app_storage):
        # Given a source user
        with source_app.app_context():
            source_user = create_source_user(
                db_session=db.session,
                source_passphrase=PassphraseGenerator.get_default().
                generate_passphrase(),
                source_app_storage=app_storage,
            )

        # And an encryption manager
        journalist_key_fingerprint, gpg_key_dir = setup_journalist_key_and_gpg_folder
        encryption_mgr = EncryptionManager(
            gpg_key_dir=gpg_key_dir,
            journalist_key_fingerprint=journalist_key_fingerprint)

        # When using the encryption manager to generate a key pair for this source user
        # It succeeds
        encryption_mgr.generate_source_key_pair(source_user)

        # And the newly-created key's fingerprint was added to Redis
        fingerprint_in_redis = encryption_mgr._redis.hget(
            encryption_mgr.REDIS_FINGERPRINT_HASH, source_user.filesystem_id)
        assert fingerprint_in_redis
        source_key_fingerprint = encryption_mgr.get_source_key_fingerprint(
            source_user.filesystem_id)
        assert fingerprint_in_redis == source_key_fingerprint

        # And the user's newly-generated public key can be retrieved
        assert encryption_mgr.get_source_public_key(source_user.filesystem_id)

        # And the key has a hardcoded creation date to avoid leaking information about when sources
        # first created their account
        source_key_details = encryption_mgr._get_source_key_details(
            source_user.filesystem_id)
        assert source_key_details
        creation_date = _parse_gpg_date_string(source_key_details["date"])
        assert creation_date.date(
        ) == EncryptionManager.DEFAULT_KEY_CREATION_DATE

        # And the user's key does not expire
        assert source_key_details["expires"] == ""
Example #10
0
    def test_submit_and_retrieve_happy_path(self,
                                            sd_servers_v2_with_clean_state,
                                            tor_browser_web_driver,
                                            firefox_web_driver):
        # Given a source user accessing the app from their browser
        source_app_nav = SourceAppNagivator(
            source_app_base_url=sd_servers_v2_with_clean_state.
            source_app_base_url,
            web_driver=tor_browser_web_driver,
        )

        # And they created an account
        source_app_nav.source_visits_source_homepage()
        source_app_nav.source_clicks_submit_documents_on_homepage()
        source_app_nav.source_continues_to_submit_page()

        # And the source user submitted a message
        submitted_message = "Confidential message with some international characters: éèö"
        source_app_nav.source_submits_a_message(message=submitted_message)
        source_app_nav.source_logs_out()

        # When a journalist logs in
        journ_app_nav = JournalistAppNavigator(
            journalist_app_base_url=sd_servers_v2_with_clean_state.
            journalist_app_base_url,
            web_driver=firefox_web_driver,
        )
        journ_app_nav.journalist_logs_in(
            username=sd_servers_v2_with_clean_state.journalist_username,
            password=sd_servers_v2_with_clean_state.journalist_password,
            otp_secret=sd_servers_v2_with_clean_state.journalist_otp_secret,
        )
        journ_app_nav.journalist_checks_messages()

        #  And they try to download the message
        #  Then it succeeds and the journalist sees correct message
        servers_sd_config = sd_servers_v2_with_clean_state.config_in_use
        retrieved_message = journ_app_nav.journalist_downloads_first_message(
            encryption_mgr_to_use_for_decryption=EncryptionManager(
                gpg_key_dir=Path(servers_sd_config.GPG_KEY_DIR),
                journalist_key_fingerprint=servers_sd_config.JOURNALIST_KEY,
            ))
        assert retrieved_message == submitted_message
    def test_submit_and_retrieve_happy_path(self, locale,
                                            sd_servers_v2_with_clean_state,
                                            tor_browser_web_driver,
                                            firefox_web_driver):
        # Given a source user accessing the app from their browser
        locale_with_commas = locale.replace("_", "-")
        source_app_nav = SourceAppNagivator(
            source_app_base_url=sd_servers_v2_with_clean_state.
            source_app_base_url,
            web_driver=tor_browser_web_driver,
            accept_languages=locale_with_commas,
        )

        # And they created an account
        source_app_nav.source_visits_source_homepage()
        source_app_nav.source_clicks_submit_documents_on_homepage()
        source_app_nav.source_continues_to_submit_page()
        source_codename = source_app_nav.source_retrieves_codename_from_hint()

        # And the source user submitted a file
        submitted_content = "Confidential file with some international characters: éèö"
        source_app_nav.source_submits_a_file(file_content=submitted_content)
        source_app_nav.source_logs_out()

        # And a journalist logs in
        journ_app_nav = JournalistAppNavigator(
            journalist_app_base_url=sd_servers_v2_with_clean_state.
            journalist_app_base_url,
            web_driver=firefox_web_driver,
        )
        journ_app_nav.journalist_logs_in(
            username=sd_servers_v2_with_clean_state.journalist_username,
            password=sd_servers_v2_with_clean_state.journalist_password,
            otp_secret=sd_servers_v2_with_clean_state.journalist_otp_secret,
        )
        journ_app_nav.journalist_checks_messages()

        # When they star and unstar the submission, then it succeeds
        self._journalist_stars_and_unstars_single_message(journ_app_nav)

        # And when they try to download the file
        # Then it succeeds and the journalist sees the correct content
        apps_sd_config = sd_servers_v2_with_clean_state.config_in_use
        retrieved_message = journ_app_nav.journalist_downloads_first_message(
            encryption_mgr_to_use_for_decryption=EncryptionManager(
                gpg_key_dir=Path(apps_sd_config.GPG_KEY_DIR),
                journalist_key_fingerprint=apps_sd_config.JOURNALIST_KEY,
            ))
        assert retrieved_message == submitted_content

        # And when they reply to the source, it succeeds
        journ_app_nav.journalist_sends_reply_to_source()

        # And when the source user comes back
        source_app_nav.source_visits_source_homepage()
        source_app_nav.source_chooses_to_login()
        source_app_nav.source_proceeds_to_login(codename=source_codename)
        save_screenshot_and_html(source_app_nav.driver, locale,
                                 "source-checks_for_reply")

        # When they delete the journalist's reply, it succeeds
        self._source_deletes_journalist_reply(source_app_nav)
        save_screenshot_and_html(source_app_nav.driver, locale,
                                 "source-deletes_reply")
Example #12
0
from flask import Flask, jsonify, request
from encryption import EncryptionManager
from studies import StudyMatcher
from validation import ValidationManager
from tests import get_test_graph
from queries import *
import uuid

TEST_GRAPH_SIZE = 20000

app = Flask(__name__)

# Setup
encryption = EncryptionManager()
study_matcher = StudyMatcher()
validation = ValidationManager()
key_session_map = {}
graph = get_test_graph(TEST_GRAPH_SIZE)


@app.route('/studies/check', methods=['GET'])
def check_for_studies():
    global encryption, study_matcher, validation
    decrypted_request = encryption.decrypt(request.args)
    user_token = decrypted_request['token']
    if validation.is_valid_token(user_token):
        user_pub_key = decrypted_request['key']
        matched_studies = study_matcher.match_request_to_studies(
            decrypted_request)
        payload = encryption.encrypt(matched_studies, user_pub_key)
        return jsonify(payload)