Example #1
0
def test_invalid_locales(config):
    """
    An invalid locale raises an error during app configuration.
    """
    fake_config = SDConfig()
    fake_config.SUPPORTED_LOCALES = [FALLBACK_LOCALE, "yy_ZZ"]
    fake_config.TRANSLATION_DIRS = Path(config.TEMP_DIR)

    with pytest.raises(UnknownLocaleError):
        journalist_app_module.create_app(fake_config)

    with pytest.raises(UnknownLocaleError):
        source_app.create_app(fake_config)
Example #2
0
def test_schema_unchanged_after_up_then_downgrade(alembic_config,
                                                  config,
                                                  migration):
    # Create the app here. Using a fixture will init the database.
    app = create_app(config)

    migrations = list_migrations(alembic_config, migration)

    if len(migrations) > 1:
        target = migrations[-2]
        upgrade(alembic_config, target)
    else:
        # The first migration is the degenerate case where we don't need to
        # get the database to some base state.
        pass

    original_schema = get_schema(app)

    upgrade(alembic_config, '+1')
    downgrade(alembic_config, '-1')

    reverted_schema = get_schema(app)

    # The initial migration is a degenerate case because it creates the table
    # 'alembic_version', but rolling back the migration doesn't clear it.
    if len(migrations) == 1:
        reverted_schema = {k: v for k, v in list(reverted_schema.items())
                           if k[2] != 'alembic_version'}

    assert_schemas_equal(reverted_schema, original_schema)
Example #3
0
def test_html_attributes(journalist_app, config):
    """Check that HTML lang and dir attributes respect locale."""

    # Then delete it because using it won't test what we want
    del journalist_app

    config.SUPPORTED_LOCALES = ["ar", "en_US"]
    app = journalist_app_module.create_app(config).test_client()
    resp = app.get("/?l=ar", follow_redirects=True)
    html = resp.data.decode("utf-8")
    assert '<html lang="ar" dir="rtl">' in html
    resp = app.get("/?l=en_US", follow_redirects=True)
    html = resp.data.decode("utf-8")
    assert '<html lang="en-US" dir="ltr">' in html

    app = source_app.create_app(config).test_client()
    resp = app.get("/?l=ar", follow_redirects=True)
    html = resp.data.decode("utf-8")
    assert '<html lang="ar" dir="rtl">' in html
    resp = app.get("/?l=en_US", follow_redirects=True)
    html = resp.data.decode("utf-8")
    assert '<html lang="en-US" dir="ltr">' in html

    # check '/generate' too because '/' uses a different template
    resp = app.post("/generate?l=ar",
                    data={"tor2web_check": 'href="fake.onion"'},
                    follow_redirects=True)
    html = resp.data.decode("utf-8")
    assert '<html lang="ar" dir="rtl">' in html
    resp = app.post("/generate?l=en_US",
                    data={"tor2web_check": 'href="fake.onion"'},
                    follow_redirects=True)
    html = resp.data.decode("utf-8")
    assert '<html lang="en-US" dir="ltr">' in html
Example #4
0
def test_no_usable_fallback_locale(journalist_app, config):
    """
    The apps fail if neither the default nor the fallback locale is usable.
    """
    fake_config = SDConfig()
    fake_config.DEFAULT_LOCALE = NEVER_LOCALE
    fake_config.SUPPORTED_LOCALES = [NEVER_LOCALE]
    fake_config.TRANSLATION_DIRS = Path(config.TEMP_DIR)

    i18n.USABLE_LOCALES = set()

    with pytest.raises(ValueError, match="in the set of usable locales"):
        journalist_app_module.create_app(fake_config)

    with pytest.raises(ValueError, match="in the set of usable locales"):
        source_app.create_app(fake_config)
Example #5
0
    def test_filters(self):
        sources = [
            'tests/i18n/code.py',
        ]
        kwargs = {
            'translations_dir': config.TEMP_DIR,
            'mapping': 'tests/i18n/babel.cfg',
            'source': sources,
            'extract_update': True,
            'compile': True,
            'verbose': logging.DEBUG,
            'version': version.__version__,
        }
        args = argparse.Namespace(**kwargs)
        manage.setup_verbosity(args)
        manage.translate_messages(args)

        manage.sh("""
        pybabel init -i {d}/messages.pot -d {d} -l en_US
        pybabel init -i {d}/messages.pot -d {d} -l fr_FR
        """.format(d=config.TEMP_DIR))

        fake_config = self.get_fake_config()
        fake_config.SUPPORTED_LOCALES = ['en_US', 'fr_FR']
        fake_config.TRANSLATION_DIRS = config.TEMP_DIR
        for app in (journalist_app.create_app(fake_config),
                    source_app.create_app(fake_config)):
            assert i18n.LOCALES == fake_config.SUPPORTED_LOCALES
            self.verify_filesizeformat(app)
            self.verify_rel_datetime_format(app)
    def test_filters(self):
        sources = [
            'tests/i18n/code.py',
        ]
        kwargs = {
            'translations_dir': config.TEMP_DIR,
            'mapping': 'tests/i18n/babel.cfg',
            'source': sources,
            'extract_update': True,
            'compile': True,
            'verbose': logging.DEBUG,
            'version': version.__version__,
        }
        args = argparse.Namespace(**kwargs)
        manage.setup_verbosity(args)
        manage.translate_messages(args)

        manage.sh("""
        pybabel init -i {d}/messages.pot -d {d} -l en_US
        pybabel init -i {d}/messages.pot -d {d} -l fr_FR
        """.format(d=config.TEMP_DIR))

        fake_config = self.get_fake_config()
        fake_config.SUPPORTED_LOCALES = ['en_US', 'fr_FR']
        fake_config.TRANSLATION_DIRS = config.TEMP_DIR
        for app in (journalist_app.create_app(fake_config),
                    source_app.create_app(fake_config)):
            assert i18n.LOCALES == fake_config.SUPPORTED_LOCALES
            self.verify_filesizeformat(app)
            self.verify_rel_datetime_format(app)
def test_alembic_head_matches_db_models(journalist_app, alembic_config,
                                        config):
    """This test is to make sure that our database models in `models.py` are
    always in sync with the schema generated by `alembic upgrade head`.
    """
    models_schema = get_schema(journalist_app)

    os.remove(config.DATABASE_FILE)

    # Create database file
    subprocess.check_call(["sqlite3", config.DATABASE_FILE, ".databases"])
    upgrade(alembic_config, "head")

    # Recreate the app to get a new SQLALCHEMY_DATABASE_URI
    app = create_app(config)
    alembic_schema = get_schema(app)

    # The initial migration creates the table 'alembic_version', but this is
    # not present in the schema created by `db.create_all()`.
    alembic_schema = {
        k: v
        for k, v in list(alembic_schema.items()) if k[2] != "alembic_version"
    }

    assert_schemas_equal(alembic_schema, models_schema)
Example #8
0
 def __init__(self, config):
     """This function MUST accept an argument named `config`.
     You will likely want to save a reference to the config in your
     class, so you can access the database later.
     """
     self.config = config
     self.app = create_app(config)
Example #9
0
    def __init__(
        self,
        config: SDConfig,
        journalist_count: int = 10,
        source_count: int = 50,
        submissions_per_source: int = 1,
        replies_per_source: int = 1,
        source_star_fraction: float = 0.1,
        source_reply_fraction: float = 0.5,
    ) -> None:
        """
        source_star_fraction and source_reply_fraction are simply the
        fraction of sources starred or replied to.
        """
        self.config = config
        self.app = create_app(config)

        self.journalist_count = journalist_count
        self.source_count = source_count
        self.submissions_per_source = submissions_per_source
        self.replies_per_source = replies_per_source
        self.source_star_fraction = source_star_fraction
        self.source_reply_fraction = source_reply_fraction

        self.journalists = []  # type: List[int]
        self.sources = []  # type: List[int]
def upgrade() -> None:
    with op.batch_alter_table("replies", schema=None) as batch_op:
        batch_op.add_column(
            sa.Column("checksum", sa.String(length=255), nullable=True))

    with op.batch_alter_table("submissions", schema=None) as batch_op:
        batch_op.add_column(
            sa.Column("checksum", sa.String(length=255), nullable=True))

    op.create_table(
        "revoked_tokens",
        sa.Column("id", sa.Integer(), nullable=False),
        sa.Column("journalist_id", sa.Integer(), nullable=True),
        sa.Column("token", sa.Text(), nullable=False),
        sa.ForeignKeyConstraint(["journalist_id"], ["journalists.id"]),
        sa.PrimaryKeyConstraint("id"),
        sa.UniqueConstraint("token"),
    )

    try:
        app = create_app(config)

        # we need an app context for the rq worker extension to work properly
        with app.app_context():
            conn = op.get_bind()
            query = sa.text(
                """SELECT submissions.id, sources.filesystem_id, submissions.filename
                               FROM submissions
                               INNER JOIN sources
                               ON submissions.source_id = sources.id
                            """)
            for (sub_id, filesystem_id, filename) in conn.execute(query):
                full_path = Storage.get_default().path(filesystem_id, filename)
                create_queue().enqueue(
                    queued_add_checksum_for_file,
                    Submission,
                    int(sub_id),
                    full_path,
                    app.config["SQLALCHEMY_DATABASE_URI"],
                )

            query = sa.text(
                """SELECT replies.id, sources.filesystem_id, replies.filename
                               FROM replies
                               INNER JOIN sources
                               ON replies.source_id = sources.id
                            """)
            for (rep_id, filesystem_id, filename) in conn.execute(query):
                full_path = Storage.get_default().path(filesystem_id, filename)
                create_queue().enqueue(
                    queued_add_checksum_for_file,
                    Reply,
                    int(rep_id),
                    full_path,
                    app.config["SQLALCHEMY_DATABASE_URI"],
                )
    except:  # noqa
        if raise_errors:
            raise
Example #11
0
    def __init__(self, config):
        Helper.__init__(self)
        self.config = config
        self.app = create_app(config)

        # as this class requires access to the Storage object, which is no longer
        # attached to app, we create it here and mock the call to return it below.
        self.storage = Storage(config.STORE_DIR, config.TEMP_DIR)
Example #12
0
    def __init__(self, config, multiplier):
        self.config = config
        self.app = create_app(config)
        self.multiplier = multiplier

        self.journalists = []
        self.sources = []
        self.submissions = []
Example #13
0
def test_i18n(journalist_app, config):
    # Then delete it because using it won't test what we want
    del journalist_app

    sources = [
        os.path.join(TESTS_DIR, "i18n/code.py"),
        os.path.join(TESTS_DIR, "i18n/template.html"),
    ]

    i18n_tool.I18NTool().main([
        "--verbose",
        "translate-messages",
        "--mapping",
        os.path.join(TESTS_DIR, "i18n/babel.cfg"),
        "--translations-dir",
        config.TEMP_DIR,
        "--sources",
        ",".join(sources),
        "--extract-update",
    ])

    pot = os.path.join(config.TEMP_DIR, "messages.pot")
    pybabel("init", "-i", pot, "-d", config.TEMP_DIR, "-l", "en_US")

    for (l, s) in (
        ("fr_FR", "code bonjour"),
        ("zh_Hans", "code chinese"),
        ("ar", "code arabic"),
        ("nb_NO", "code norwegian"),
        ("es_ES", "code spanish"),
    ):
        pybabel("init", "-i", pot, "-d", config.TEMP_DIR, "-l", l)
        po = os.path.join(config.TEMP_DIR, l, "LC_MESSAGES/messages.po")
        sed("-i", "-e",
            '/code hello i18n/,+1s/msgstr ""/msgstr "{}"/'.format(s), po)

    i18n_tool.I18NTool().main([
        "--verbose",
        "translate-messages",
        "--translations-dir",
        config.TEMP_DIR,
        "--compile",
    ])

    fake_config = SDConfig()
    fake_config.SUPPORTED_LOCALES = [
        "ar", "en_US", "fr_FR", "nb_NO", "zh_Hans"
    ]
    fake_config.TRANSLATION_DIRS = Path(config.TEMP_DIR)

    # Use our config (and not an app fixture) because the i18n module
    # grabs values at init time and we can't inject them later.
    for app in (journalist_app_module.create_app(fake_config),
                source_app.create_app(fake_config)):
        with app.app_context():
            db.create_all()
        assert list(i18n.LOCALES.keys()) == fake_config.SUPPORTED_LOCALES
        verify_i18n(app)
Example #14
0
def upgrade():
    conn = op.get_bind()
    submissions = conn.execute(
        sa.text(raw_sql_grab_orphaned_objects('submissions'))).fetchall()

    replies = conn.execute(sa.text(
        raw_sql_grab_orphaned_objects('replies'))).fetchall()

    try:
        app = create_app(config)
        with app.app_context():
            for submission in submissions:
                try:
                    conn.execute(
                        sa.text("""
                        DELETE FROM submissions
                        WHERE id=:id
                    """).bindparams(id=submission.id))

                    path = app.storage.path_without_filesystem_id(
                        submission.filename)
                    app.storage.move_to_shredder(path)
                except NoFileFoundException:
                    # The file must have been deleted by the admin, remove the row
                    conn.execute(
                        sa.text("""
                        DELETE FROM submissions
                        WHERE id=:id
                    """).bindparams(id=submission.id))
                except TooManyFilesException:
                    pass

            for reply in replies:
                try:
                    conn.execute(
                        sa.text("""
                            DELETE FROM replies
                            WHERE id=:id
                        """).bindparams(id=reply.id))

                    path = app.storage.path_without_filesystem_id(
                        reply.filename)
                    app.storage.move_to_shredder(path)
                except NoFileFoundException:
                    # The file must have been deleted by the admin, remove the row
                    conn.execute(
                        sa.text("""
                            DELETE FROM replies
                            WHERE id=:id
                        """).bindparams(id=reply.id))
                except TooManyFilesException:
                    pass
    except:  # noqa
        if raise_errors:
            raise
Example #15
0
def test_i18n(journalist_app, config):
    # Then delete it because using it won't test what we want
    del journalist_app

    sources = [
        os.path.join(TESTS_DIR, 'i18n/code.py'),
        os.path.join(TESTS_DIR, 'i18n/template.html'),
    ]

    i18n_tool.I18NTool().main([
        '--verbose',
        'translate-messages',
        '--mapping',
        os.path.join(TESTS_DIR, 'i18n/babel.cfg'),
        '--translations-dir',
        config.TEMP_DIR,
        '--sources',
        ",".join(sources),
        '--extract-update',
    ])

    pot = os.path.join(config.TEMP_DIR, 'messages.pot')
    pybabel('init', '-i', pot, '-d', config.TEMP_DIR, '-l', 'en_US')

    for (l, s) in (('fr_FR', 'code bonjour'), ('zh_Hans_CN', 'code chinese'),
                   ('ar', 'code arabic'), ('nb_NO', 'code norwegian'),
                   ('es_ES', 'code spanish')):
        pybabel('init', '-i', pot, '-d', config.TEMP_DIR, '-l', l)
        po = os.path.join(config.TEMP_DIR, l, 'LC_MESSAGES/messages.po')
        sed('-i', '-e',
            '/code hello i18n/,+1s/msgstr ""/msgstr "{}"/'.format(s), po)

    i18n_tool.I18NTool().main([
        '--verbose',
        'translate-messages',
        '--translations-dir',
        config.TEMP_DIR,
        '--compile',
    ])

    fake_config = SDConfig()
    fake_config.SUPPORTED_LOCALES = [
        'en_US', 'fr_FR', 'zh_Hans_CN', 'ar', 'nb_NO'
    ]
    fake_config.TRANSLATION_DIRS = config.TEMP_DIR

    # Use our config (and not an app fixture) because the i18n module
    # grabs values at init time and we can't inject them later.
    for app in (journalist_app_module.create_app(fake_config),
                source_app.create_app(fake_config)):
        with app.app_context():
            db.create_all()
        assert i18n.LOCALES == fake_config.SUPPORTED_LOCALES
        verify_i18n(app)
Example #16
0
    def test_i18n(self):
        sources = [
            'tests/i18n/code.py',
            'tests/i18n/template.html',
        ]
        kwargs = {
            'translations_dir': config.TEMP_DIR,
            'mapping': 'tests/i18n/babel.cfg',
            'source': sources,
            'extract_update': True,
            'compile': True,
            'verbose': logging.DEBUG,
            'version': version.__version__,
        }
        args = argparse.Namespace(**kwargs)
        manage.setup_verbosity(args)
        manage.translate_messages(args)

        manage.sh("""
        pybabel init -i {d}/messages.pot -d {d} -l en_US

        pybabel init -i {d}/messages.pot -d {d} -l fr_FR
        sed -i -e '/code hello i18n/,+1s/msgstr ""/msgstr "code bonjour"/' \
              {d}/fr_FR/LC_MESSAGES/messages.po

        pybabel init -i {d}/messages.pot -d {d} -l zh_Hans_CN
        sed -i -e '/code hello i18n/,+1s/msgstr ""/msgstr "code chinese"/' \
              {d}/zh_Hans_CN/LC_MESSAGES/messages.po

        pybabel init -i {d}/messages.pot -d {d} -l ar
        sed -i -e '/code hello i18n/,+1s/msgstr ""/msgstr "code arabic"/' \
              {d}/ar/LC_MESSAGES/messages.po

        pybabel init -i {d}/messages.pot -d {d} -l nb_NO
        sed -i -e '/code hello i18n/,+1s/msgstr ""/msgstr "code norwegian"/' \
              {d}/nb_NO/LC_MESSAGES/messages.po

        pybabel init -i {d}/messages.pot -d {d} -l es_ES
        sed -i -e '/code hello i18n/,+1s/msgstr ""/msgstr "code spanish"/' \
              {d}/es_ES/LC_MESSAGES/messages.po
        """.format(d=config.TEMP_DIR))

        manage.translate_messages(args)

        fake_config = self.get_fake_config()
        fake_config.SUPPORTED_LOCALES = [
            'en_US', 'fr_FR', 'zh_Hans_CN', 'ar', 'nb_NO'
        ]
        fake_config.TRANSLATION_DIRS = config.TEMP_DIR
        for app in (journalist_app.create_app(fake_config),
                    source_app.create_app(fake_config)):
            assert i18n.LOCALES == fake_config.SUPPORTED_LOCALES
            self.verify_i18n(app)
Example #17
0
def main(staging: bool = False) -> None:
    app = journalist_app.create_app(config)
    with app.app_context():
        # Add two test users
        test_password = "******"
        test_otp_secret = "JHCOGO7VCER3EJ4L"

        journalist_who_saw = add_test_user(
            "journalist",
            test_password,
            test_otp_secret,
            is_admin=True
        )

        if staging:
            return

        dellsberg = add_test_user(
            "dellsberg",
            test_password,
            test_otp_secret,
            is_admin=False
        )

        journalist_tobe_deleted = add_test_user("clarkkent",
                                                test_password,
                                                test_otp_secret,
                                                is_admin=False,
                                                first_name="Clark",
                                                last_name="Kent")

        NUM_SOURCES = os.getenv('NUM_SOURCES', 3)
        if NUM_SOURCES == "ALL":
            # We ingest two strings per source, so this will create the required
            # number of sources to include all special strings
            NUM_SOURCES = math.ceil(len(strings) / 2)

        # Create source data
        num_sources = int(NUM_SOURCES)
        for i in range(num_sources):
            # For the first source, the journalist who replied will be deleted, otherwise dellsberg
            journalist_who_replied = journalist_tobe_deleted if i == 0 else dellsberg

            create_source_data(
                i,
                num_sources,
                journalist_who_replied,
                journalist_who_saw
            )

        # Now let us delete one journalist
        db.session.delete(journalist_tobe_deleted)
        db.session.commit()
Example #18
0
    def test_i18n(self):
        sources = [
            'tests/i18n/code.py',
            'tests/i18n/template.html',
        ]
        kwargs = {
            'translations_dir': config.TEMP_DIR,
            'mapping': 'tests/i18n/babel.cfg',
            'source': sources,
            'extract_update': True,
            'compile': True,
            'verbose': logging.DEBUG,
            'version': version.__version__,
        }
        args = argparse.Namespace(**kwargs)
        manage.setup_verbosity(args)
        manage.translate_messages(args)

        manage.sh("""
        pybabel init -i {d}/messages.pot -d {d} -l en_US

        pybabel init -i {d}/messages.pot -d {d} -l fr_FR
        sed -i -e '/code hello i18n/,+1s/msgstr ""/msgstr "code bonjour"/' \
              {d}/fr_FR/LC_MESSAGES/messages.po

        pybabel init -i {d}/messages.pot -d {d} -l zh_Hans_CN
        sed -i -e '/code hello i18n/,+1s/msgstr ""/msgstr "code chinese"/' \
              {d}/zh_Hans_CN/LC_MESSAGES/messages.po

        pybabel init -i {d}/messages.pot -d {d} -l ar
        sed -i -e '/code hello i18n/,+1s/msgstr ""/msgstr "code arabic"/' \
              {d}/ar/LC_MESSAGES/messages.po

        pybabel init -i {d}/messages.pot -d {d} -l nb_NO
        sed -i -e '/code hello i18n/,+1s/msgstr ""/msgstr "code norwegian"/' \
              {d}/nb_NO/LC_MESSAGES/messages.po

        pybabel init -i {d}/messages.pot -d {d} -l es_ES
        sed -i -e '/code hello i18n/,+1s/msgstr ""/msgstr "code spanish"/' \
              {d}/es_ES/LC_MESSAGES/messages.po
        """.format(d=config.TEMP_DIR))

        manage.translate_messages(args)

        fake_config = self.get_fake_config()
        fake_config.SUPPORTED_LOCALES = [
            'en_US', 'fr_FR', 'zh_Hans_CN', 'ar', 'nb_NO']
        fake_config.TRANSLATION_DIRS = config.TEMP_DIR
        for app in (journalist_app.create_app(fake_config),
                    source_app.create_app(fake_config)):
            assert i18n.LOCALES == fake_config.SUPPORTED_LOCALES
            self.verify_i18n(app)
Example #19
0
def test_supported_locales(config):
    fake_config = SDConfig()

    # Check that an invalid locale raises an error during app
    # configuration.
    fake_config.SUPPORTED_LOCALES = ['en_US', 'yy_ZZ']
    fake_config.TRANSLATION_DIRS = Path(config.TEMP_DIR)

    with pytest.raises(UnknownLocaleError):
        journalist_app_module.create_app(fake_config)

    with pytest.raises(UnknownLocaleError):
        source_app.create_app(fake_config)

    # Check that a valid but unsupported locale raises an error during
    # app configuration.
    fake_config.SUPPORTED_LOCALES = ['en_US', 'wae_CH']
    fake_config.TRANSLATION_DIRS = Path(config.TEMP_DIR)

    with pytest.raises(ValueError, match="not in the set of translated locales"):
        journalist_app_module.create_app(fake_config)

    with pytest.raises(ValueError, match="not in the set of translated locales"):
        source_app.create_app(fake_config)
Example #20
0
def test_unusable_default_but_usable_fallback_locale(config, caplog):
    """
    The apps start even if the default locale is unusable, as along as the fallback locale is
    usable, but log an error for OSSEC to pick up.
    """
    fake_config = SDConfig()
    fake_config.DEFAULT_LOCALE = NEVER_LOCALE
    fake_config.SUPPORTED_LOCALES = [NEVER_LOCALE, FALLBACK_LOCALE]
    fake_config.TRANSLATION_DIRS = Path(config.TEMP_DIR)

    for app in (journalist_app_module.create_app(fake_config),
                source_app.create_app(fake_config)):
        with app.app_context():
            assert NEVER_LOCALE in caplog.text
            assert "not in the set of usable locales" in caplog.text
Example #21
0
def test_valid_but_unusable_locales(config, caplog):
    """
    The apps start with one or more unusable, but still valid, locales, but log an error for
    OSSEC to pick up.
    """
    fake_config = SDConfig()

    fake_config.SUPPORTED_LOCALES = [FALLBACK_LOCALE, "wae_CH"]
    fake_config.TRANSLATION_DIRS = Path(config.TEMP_DIR)

    for app in (journalist_app_module.create_app(fake_config),
                source_app.create_app(fake_config)):
        with app.app_context():
            assert "wae" in caplog.text
            assert "not in the set of usable locales" in caplog.text
Example #22
0
    def test_html_en_lang_correct(self):
        fake_config = self.get_fake_config()
        app = journalist_app.create_app(fake_config).test_client()
        resp = app.get('/', follow_redirects=True)
        html = resp.data.decode('utf-8')
        assert re.compile('<html .*lang="en".*>').search(html), html

        app = source_app.create_app(fake_config).test_client()
        resp = app.get('/', follow_redirects=True)
        html = resp.data.decode('utf-8')
        assert re.compile('<html .*lang="en".*>').search(html), html

        # check '/generate' too because '/' uses a different template
        resp = app.get('/generate', follow_redirects=True)
        html = resp.data.decode('utf-8')
        assert re.compile('<html .*lang="en".*>').search(html), html
Example #23
0
    def test_html_en_lang_correct(self):
        fake_config = self.get_fake_config()
        app = journalist_app.create_app(fake_config).test_client()
        resp = app.get('/', follow_redirects=True)
        html = resp.data.decode('utf-8')
        assert re.compile('<html .*lang="en".*>').search(html), html

        app = source_app.create_app(fake_config).test_client()
        resp = app.get('/', follow_redirects=True)
        html = resp.data.decode('utf-8')
        assert re.compile('<html .*lang="en".*>').search(html), html

        # check '/generate' too because '/' uses a different template
        resp = app.get('/generate', follow_redirects=True)
        html = resp.data.decode('utf-8')
        assert re.compile('<html .*lang="en".*>').search(html), html
Example #24
0
def test_add_checksum_for_file(config, app_storage, db_model):
    """
    Check that when we execute the `add_checksum_for_file` function, the database object is
    correctly updated with the actual hash of the file.

    We have to create our own app in order to have more control over the SQLAlchemy sessions. The
    fixture pushes a single app context that forces us to work within a single transaction.
    """
    app = create_app(config)

    test_storage = app_storage

    with app.app_context():
        db.create_all()
        source_user = create_source_user(
            db_session=db.session,
            source_passphrase=PassphraseGenerator.get_default().
            generate_passphrase(),
            source_app_storage=test_storage,
        )
        source = source_user.get_db_record()
        target_file_path = test_storage.path(source.filesystem_id,
                                             "1-foo-msg.gpg")
        test_message = b"hash me!"
        expected_hash = "f1df4a6d8659471333f7f6470d593e0911b4d487856d88c83d2d187afa195927"

        with open(target_file_path, "wb") as f:
            f.write(test_message)

        if db_model == Submission:
            db_obj = Submission(source, target_file_path, app_storage)
        else:
            journalist, _ = utils.db_helper.init_journalist()
            db_obj = Reply(journalist, source, target_file_path, app_storage)

        db.session.add(db_obj)
        db.session.commit()
        db_obj_id = db_obj.id

    queued_add_checksum_for_file(db_model, db_obj_id, target_file_path,
                                 app.config["SQLALCHEMY_DATABASE_URI"])

    with app.app_context():
        # requery to get a new object
        db_obj = db_model.query.filter_by(id=db_obj_id).one()
        assert db_obj.checksum == "sha256:" + expected_hash
Example #25
0
    def test_html_fr_lang_correct(self):
        """Check that when the locale is fr_FR the lang property is correct"""
        fake_config = self.get_fake_config()
        fake_config.SUPPORTED_LOCALES = ['fr_FR', 'en_US']
        app = journalist_app.create_app(fake_config).test_client()
        resp = app.get('/?l=fr_FR', follow_redirects=True)
        html = resp.data.decode('utf-8')
        assert re.compile('<html .*lang="fr".*>').search(html), html

        app = source_app.create_app(fake_config).test_client()
        resp = app.get('/?l=fr_FR', follow_redirects=True)
        html = resp.data.decode('utf-8')
        assert re.compile('<html .*lang="fr".*>').search(html), html

        # check '/generate' too because '/' uses a different template
        resp = app.get('/generate?l=fr_FR', follow_redirects=True)
        html = resp.data.decode('utf-8')
        assert re.compile('<html .*lang="fr".*>').search(html), html
Example #26
0
def test_html_en_lang_correct(journalist_app, config):
    # Then delete it because using it won't test what we want
    del journalist_app

    app = journalist_app_module.create_app(config).test_client()
    resp = app.get('/', follow_redirects=True)
    html = resp.data.decode('utf-8')
    assert re.compile('<html .*lang="en".*>').search(html), html

    app = source_app.create_app(config).test_client()
    resp = app.get('/', follow_redirects=True)
    html = resp.data.decode('utf-8')
    assert re.compile('<html .*lang="en".*>').search(html), html

    # check '/generate' too because '/' uses a different template
    resp = app.get('/generate', follow_redirects=True)
    html = resp.data.decode('utf-8')
    assert re.compile('<html .*lang="en".*>').search(html), html
Example #27
0
    def test_html_fr_lang_correct(self):
        """Check that when the locale is fr_FR the lang property is correct"""
        fake_config = self.get_fake_config()
        fake_config.SUPPORTED_LOCALES = ['fr_FR', 'en_US']
        app = journalist_app.create_app(fake_config).test_client()
        resp = app.get('/?l=fr_FR', follow_redirects=True)
        html = resp.data.decode('utf-8')
        assert re.compile('<html .*lang="fr".*>').search(html), html

        app = source_app.create_app(fake_config).test_client()
        resp = app.get('/?l=fr_FR', follow_redirects=True)
        html = resp.data.decode('utf-8')
        assert re.compile('<html .*lang="fr".*>').search(html), html

        # check '/generate' too because '/' uses a different template
        resp = app.get('/generate?l=fr_FR', follow_redirects=True)
        html = resp.data.decode('utf-8')
        assert re.compile('<html .*lang="fr".*>').search(html), html
Example #28
0
def test_html_en_lang_correct(journalist_app, config):
    # Then delete it because using it won't test what we want
    del journalist_app

    app = journalist_app_module.create_app(config).test_client()
    resp = app.get("/", follow_redirects=True)
    html = resp.data.decode("utf-8")
    assert re.compile('<html lang="en-US".*>').search(html), html

    app = source_app.create_app(config).test_client()
    resp = app.get("/", follow_redirects=True)
    html = resp.data.decode("utf-8")
    assert re.compile('<html lang="en-US".*>').search(html), html

    # check '/generate' too because '/' uses a different template
    resp = app.post("/generate",
                    data={"tor2web_check": 'href="fake.onion"'},
                    follow_redirects=True)
    html = resp.data.decode("utf-8")
    assert re.compile('<html lang="en-US".*>').search(html), html
Example #29
0
def test_html_fr_lang_correct(journalist_app, config):
    """Check that when the locale is fr_FR the lang property is correct"""

    # Then delete it because using it won't test what we want
    del journalist_app

    config.SUPPORTED_LOCALES = ['fr_FR', 'en_US']
    app = journalist_app_module.create_app(config).test_client()
    resp = app.get('/?l=fr_FR', follow_redirects=True)
    html = resp.data.decode('utf-8')
    assert re.compile('<html .*lang="fr".*>').search(html), html

    app = source_app.create_app(config).test_client()
    resp = app.get('/?l=fr_FR', follow_redirects=True)
    html = resp.data.decode('utf-8')
    assert re.compile('<html .*lang="fr".*>').search(html), html

    # check '/generate' too because '/' uses a different template
    resp = app.get('/generate?l=fr_FR', follow_redirects=True)
    html = resp.data.decode('utf-8')
    assert re.compile('<html .*lang="fr".*>').search(html), html
Example #30
0
def load(args: argparse.Namespace) -> None:
    """
    Populate the database.
    """
    if args.seed:
        random.seed(args.seed)

    if not os.environ.get("SECUREDROP_ENV"):
        os.environ["SECUREDROP_ENV"] = "dev"

    app = journalist_app.create_app(config)
    with app.app_context():
        journalists = create_default_journalists()

        add_journalists(args)

        add_sources(args, journalists)

        # delete one journalist
        _, _, journalist_to_be_deleted = journalists
        journalist_to_be_deleted.delete()
        db.session.commit()
Example #31
0
def test_add_checksum_for_file(config, db_model):
    '''
    Check that when we execute the `add_checksum_for_file` function, the database object is
    correctly updated with the actual hash of the file.

    We have to create our own app in order to have more control over the SQLAlchemy sessions. The
    fixture pushes a single app context that forces us to work within a single transaction.
    '''
    app = create_app(config)

    with app.app_context():
        db.create_all()
        source, _ = utils.db_helper.init_source_without_keypair()
        target_file_path = app.storage.path(source.filesystem_id, '1-foo-msg.gpg')
        test_message = b'hash me!'
        expected_hash = 'f1df4a6d8659471333f7f6470d593e0911b4d487856d88c83d2d187afa195927'

        with open(target_file_path, 'wb') as f:
            f.write(test_message)

        if db_model == Submission:
            db_obj = Submission(source, target_file_path)
        else:
            journalist, _ = utils.db_helper.init_journalist()
            db_obj = Reply(journalist, source, target_file_path)

        db.session.add(db_obj)
        db.session.commit()
        db_obj_id = db_obj.id

    queued_add_checksum_for_file(db_model,
                                 db_obj_id,
                                 target_file_path,
                                 app.config['SQLALCHEMY_DATABASE_URI'])

    with app.app_context():
        # requery to get a new object
        db_obj = db_model.query.filter_by(id=db_obj_id).one()
        assert db_obj.checksum == 'sha256:' + expected_hash
Example #32
0
def test_html_fr_lang_correct(journalist_app, config):
    """Check that when the locale is fr_FR the lang property is correct"""

    # Then delete it because using it won't test what we want
    del journalist_app

    config.SUPPORTED_LOCALES = ["fr_FR", "en_US"]
    app = journalist_app_module.create_app(config).test_client()
    resp = app.get("/?l=fr_FR", follow_redirects=True)
    html = resp.data.decode("utf-8")
    assert re.compile('<html lang="fr-FR".*>').search(html), html

    app = source_app.create_app(config).test_client()
    resp = app.get("/?l=fr_FR", follow_redirects=True)
    html = resp.data.decode("utf-8")
    assert re.compile('<html lang="fr-FR".*>').search(html), html

    # check '/generate' too because '/' uses a different template
    resp = app.post("/generate?l=fr_FR",
                    data={"tor2web_check": 'href="fake.onion"'},
                    follow_redirects=True)
    html = resp.data.decode("utf-8")
    assert re.compile('<html lang="fr-FR".*>').search(html), html
def main(staging=False):
    app = journalist_app.create_app(config)
    with app.app_context():
        # Add two test users
        test_password = "******"
        test_otp_secret = "JHCOGO7VCER3EJ4L"

        add_test_user("journalist",
                      test_password,
                      test_otp_secret,
                      is_admin=True)

        if staging:
            return

        add_test_user("dellsberg",
                      test_password,
                      test_otp_secret,
                      is_admin=False)

        # Add test sources and submissions
        num_sources = int(os.getenv('NUM_SOURCES', 2))
        for _ in range(num_sources):
            create_source_and_submissions()
 def __init__(self, config):
     self.config = config
     self.app = create_app(config)
Example #35
0
# -*- coding: utf-8 -*-

import config

from journalist_app import create_app

app = create_app(config)


if __name__ == "__main__":  # pragma: no cover
    debug = getattr(config, 'env', 'prod') != 'prod'
    app.run(debug=debug, host='0.0.0.0', port=8081)