def test_warning_appears_if_orbot_is_used(self, sd_servers_v2,
                                              orbot_web_driver):
        # Given a user
        navigator = SourceAppNagivator(
            source_app_base_url=sd_servers_v2.source_app_base_url,
            # Who is using Orbot instead of the (desktop) Tor browser
            web_driver=orbot_web_driver,
        )

        # When they access the source app's home page
        navigator.source_visits_source_homepage()

        # Then they see a warning
        warning_banner = navigator.driver.find_element_by_id("browser-android")
        assert warning_banner.is_displayed()
        assert "use the desktop version of Tor Browser" in warning_banner.text

        # And they are able to dismiss the warning
        warning_dismiss_button = navigator.driver.find_element_by_id(
            "browser-android-close")
        warning_dismiss_button.click()

        def warning_banner_is_hidden():
            assert warning_banner.is_displayed() is False

        navigator.nav_helper.wait_for(warning_banner_is_hidden)
    def test_warning_appears_if_tor_browser_not_in_use(self, sd_servers_v2,
                                                       firefox_web_driver):
        # Given a user
        navigator = SourceAppNagivator(
            source_app_base_url=sd_servers_v2.source_app_base_url,
            # Who is using Firefox instead of the tor browser
            web_driver=firefox_web_driver,
        )

        # When they access the source app's home page
        navigator.source_visits_source_homepage()

        # Then they see a warning
        warning_banner = navigator.driver.find_element_by_id("browser-tb")
        assert warning_banner.is_displayed()
        assert "It is recommended to use Tor Browser" in warning_banner.text

        # And they are able to dismiss the warning
        warning_dismiss_button = navigator.driver.find_element_by_id(
            "browser-tb-close")
        warning_dismiss_button.click()

        def warning_banner_is_hidden():
            assert warning_banner.is_displayed() is False

        navigator.nav_helper.wait_for(warning_banner_is_hidden)
    def test_source_session_timeout(self, locale, _sd_servers_with_short_timeout):
        # Given a source user accessing the app from their browser
        locale_with_commas = locale.replace("_", "-")
        with SourceAppNagivator.using_tor_browser_web_driver(
            source_app_base_url=_sd_servers_with_short_timeout.source_app_base_url,
            accept_languages=locale_with_commas,
        ) as navigator:

            # And they're logged in and are using the app
            navigator.source_visits_source_homepage()
            navigator.source_clicks_submit_documents_on_homepage()
            navigator.source_continues_to_submit_page()

            # And their session just expired
            time.sleep(SESSION_EXPIRATION_SECONDS + 1)

            # When the source user reloads the page
            navigator.driver.refresh()

            # Then the source user sees the "session expired" message
            notification = navigator.driver.find_element_by_class_name("error")
            assert notification.text
            if locale == "en_US":
                expected_text = "You were logged out due to inactivity."
                assert expected_text in notification.text

            save_screenshot_and_html(navigator.driver, locale, "source-session_timeout")
    def test_warning_high_security(self, sd_servers_v2,
                                   tor_browser_web_driver):
        # Given a user
        navigator = SourceAppNagivator(
            source_app_base_url=sd_servers_v2.source_app_base_url,
            # Who is using the Tor browser
            web_driver=tor_browser_web_driver,
        )

        # When they access the source app's home page
        navigator.source_visits_source_homepage()

        # Then they see a warning
        banner = navigator.driver.find_element_by_id("browser-security-level")
        assert banner.is_displayed()
        assert "Security Level is too low" in banner.text
    def test_codenames_exceed_max_cookie_size(self, sd_servers_v2, tor_browser_web_driver):
        """Test generation of enough codenames that the resulting cookie exceeds the recommended
        `werkzeug.Response.max_cookie_size` = 4093 bytes. (#6043)
        """
        navigator = SourceAppNagivator(
            source_app_base_url=sd_servers_v2.source_app_base_url,
            web_driver=tor_browser_web_driver,
        )

        too_many = 2 * (werkzeug.Response.max_cookie_size // len(VALID_PASSWORD))
        for _ in range(too_many):
            navigator.source_visits_source_homepage()
            navigator.source_clicks_submit_documents_on_homepage()

        navigator.source_continues_to_submit_page()
    def test_source_cancels_at_submit_page(self, sd_servers_v2, tor_browser_web_driver):
        # Given a source user who created an account
        source_app_nav = SourceAppNagivator(
            source_app_base_url=sd_servers_v2.source_app_base_url,
            web_driver=tor_browser_web_driver,
        )
        source_app_nav.source_visits_source_homepage()
        source_app_nav.source_clicks_submit_documents_on_homepage()
        source_app_nav.source_continues_to_submit_page()

        # When they click on the cancel button on the submit page, it succeeds
        source_app_nav.nav_helper.safe_click_by_css_selector(".form-controls a")

        # And the right message is displayed
        heading = source_app_nav.driver.find_element_by_id("submit-heading")
        assert "Submit Files or Messages" == heading.text
    def test_submission_notifications_on_first_login(self, sd_servers_v2, tor_browser_web_driver):
        navigator = SourceAppNagivator(
            source_app_base_url=sd_servers_v2.source_app_base_url,
            web_driver=tor_browser_web_driver,
        )

        # Given a source user who creates an account
        navigator.source_visits_source_homepage()
        navigator.source_clicks_submit_documents_on_homepage()
        navigator.source_continues_to_submit_page()

        # When they submit a message during their first login
        # Then it succeeds
        confirmation_text_first_submission = navigator.source_submits_a_message()

        # And they see the expected confirmation messages for a first submission on first login
        assert self.FIRST_SUBMISSION_TEXT in confirmation_text_first_submission

        # And when they submit a second message
        confirmation_text_second_submission = navigator.source_submits_a_message()

        # Then they don't see the messages since it's not their first submission
        assert self.FIRST_SUBMISSION_TEXT not in confirmation_text_second_submission
    def test_source_cancels_at_login_page(self, sd_servers_v2, tor_browser_web_driver):
        # Given a source user who goes to the login page
        source_app_nav = SourceAppNagivator(
            source_app_base_url=sd_servers_v2.source_app_base_url,
            web_driver=tor_browser_web_driver,
        )
        source_app_nav.source_visits_source_homepage()
        source_app_nav.source_chooses_to_login()

        # When they click on the cancel button on the login page, it succeeds
        source_app_nav.nav_helper.safe_click_by_css_selector(".form-controls a")
        source_app_nav.driver.get(sd_servers_v2.source_app_base_url)
        assert source_app_nav._is_on_source_homepage()
    def test_index_and_logout(self, locale, sd_servers_v2):
        # Given a source user accessing the app from their browser
        locale_with_commas = locale.replace("_", "-")
        with SourceAppNagivator.using_tor_browser_web_driver(
            source_app_base_url=sd_servers_v2.source_app_base_url,
            accept_languages=locale_with_commas,
        ) as navigator:

            # And they have disabled JS in their browser
            disable_js(navigator.driver)

            # When they first login, it succeeds
            navigator.source_visits_source_homepage()
            save_screenshot_and_html(navigator.driver, locale, "source-index")

            navigator.source_clicks_submit_documents_on_homepage()
            navigator.source_continues_to_submit_page()

            # And when they logout, it succeeds
            navigator.source_logs_out()
            save_screenshot_and_html(navigator.driver, locale, "source-logout_page")
Beispiel #10
0
    def test_login(self, locale, sd_servers_v2_with_clean_state,
                   tor_browser_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()

        # Take a screenshot of the login page
        source_app_nav.source_chooses_to_login()
        save_screenshot_and_html(source_app_nav.driver, locale, "source-login")

        # Take a screenshot of entering text in the login form
        source_app_nav.nav_helper.safe_send_keys_by_id(
            "codename", "ascension hypertext concert synopses")
        save_screenshot_and_html(source_app_nav.driver, locale,
                                 "source-enter-codename-in-login")
Beispiel #11
0
    def test(self, locale, sd_servers_v2_with_clean_state,
             tor_browser_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()

        # Take a screenshot of the "account created" page
        source_app_nav.source_clicks_submit_documents_on_homepage()
        save_screenshot_and_html(source_app_nav.driver, locale,
                                 "source-generate")

        # Take a screenshot of showing the codename hint
        source_app_nav.source_continues_to_submit_page()
        source_app_nav.source_retrieves_codename_from_hint()
        save_screenshot_and_html(source_app_nav.driver, locale,
                                 "source-lookup-shows-codename")

        # Take a screenshot of entering text in the message field
        source_app_nav.nav_helper.safe_send_keys_by_id("msg",
                                                       "Secret message éè")
        save_screenshot_and_html(source_app_nav.driver, locale,
                                 "source-submission_entered_text")

        # Take a screenshot of submitting a file
        source_app_nav.source_submits_a_file()
        save_screenshot_and_html(source_app_nav.driver, locale,
                                 "source-lookup")

        # Take a screenshot of doing a second submission
        source_app_nav.source_submits_a_message()
        save_screenshot_and_html(source_app_nav.driver, locale,
                                 "source-next_submission_flashed_message")
Beispiel #12
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")
    def test_generate_and_refresh_codenames_in_multiple_tabs(
        self, sd_servers_v2, tor_browser_web_driver
    ):
        navigator = SourceAppNagivator(
            source_app_base_url=sd_servers_v2.source_app_base_url,
            web_driver=tor_browser_web_driver,
        )

        # Given a user who generated a codename in Tab A
        tab_a = navigator.driver.window_handles[0]
        navigator.source_visits_source_homepage()
        navigator.source_clicks_submit_documents_on_homepage()
        codename_a1 = self._extract_generated_codename(navigator)

        # And they then re-generated their codename in Tab
        navigator.source_visits_source_homepage()
        navigator.source_clicks_submit_documents_on_homepage()
        codename_a2 = self._extract_generated_codename(navigator)
        assert codename_a1 != codename_a2

        # And they then opened a new tab, Tab B
        navigator.driver.execute_script("window.open('about:blank', '_blank')")
        tab_b = navigator.driver.window_handles[1]
        navigator.driver.switch_to.window(tab_b)
        assert tab_a != tab_b

        # And they also generated another codename in Tab B
        navigator.source_visits_source_homepage()
        navigator.source_clicks_submit_documents_on_homepage()
        codename_b = self._extract_generated_codename(navigator)
        assert codename_a2 != codename_b

        # And they ended up creating their account and submitting documents in Tab A
        navigator.driver.switch_to.window(tab_a)
        navigator.source_continues_to_submit_page()
        self._assert_is_on_lookup_page(navigator)
        assert navigator.source_retrieves_codename_from_hint() == codename_a2
        navigator.source_submits_a_message()

        # When they try to re-generate a codename in Tab B
        navigator.driver.switch_to.window(tab_b)
        navigator.source_visits_source_homepage()
        navigator.nav_helper.safe_click_by_css_selector("#started-form button")

        # Then they get redirected to /lookup with the corresponding flash message
        self._assert_is_on_lookup_page(navigator)
        notification = self._extract_flash_message_content(navigator)
        if not navigator.accept_languages:
            assert "You were redirected because you are already logged in." in notification

        # And the user's actual codename is the expected one
        assert navigator.source_retrieves_codename_from_hint() == codename_a2
    def test_generate_codenames_in_multiple_tabs(self, sd_servers_v2, tor_browser_web_driver):
        navigator = SourceAppNagivator(
            source_app_base_url=sd_servers_v2.source_app_base_url,
            web_driver=tor_browser_web_driver,
        )

        # Given a user who generated a codename in Tab A
        tab_a = navigator.driver.window_handles[0]
        navigator.source_visits_source_homepage()
        navigator.source_clicks_submit_documents_on_homepage()
        codename_a = self._extract_generated_codename(navigator)

        # And they then opened a new tab, Tab B
        navigator.driver.execute_script("window.open('about:blank', '_blank')")
        tab_b = navigator.driver.window_handles[1]
        navigator.driver.switch_to.window(tab_b)
        assert tab_a != tab_b

        # And they also generated another codename in Tab B
        navigator.source_visits_source_homepage()
        navigator.source_clicks_submit_documents_on_homepage()
        codename_b = self._extract_generated_codename(navigator)
        assert codename_a != codename_b

        # And they ended up creating their account and submitting documents in Tab A
        navigator.driver.switch_to.window(tab_a)
        navigator.source_continues_to_submit_page()
        self._assert_is_on_lookup_page(navigator)
        assert navigator.source_retrieves_codename_from_hint() == codename_a
        navigator.source_submits_a_message()

        # When the user tries to create an account and submit documents in Tab B
        navigator.driver.switch_to.window(tab_b)
        navigator.source_continues_to_submit_page()

        # Then the submission fails and the user sees the corresponding flash message in Tab B
        self._assert_is_on_lookup_page(navigator)
        notification = self._extract_flash_message_content(navigator)
        if not navigator.accept_languages:
            assert "You are already logged in." in notification

        # And the user's actual codename is the one initially generated in Tab A
        assert navigator.source_retrieves_codename_from_hint() == codename_a
    def test_no_codename_hint_on_second_login(self, sd_servers_v2, tor_browser_web_driver):
        navigator = SourceAppNagivator(
            source_app_base_url=sd_servers_v2.source_app_base_url,
            web_driver=tor_browser_web_driver,
        )

        # Given a source user who creates an account
        # When they first login
        navigator.source_visits_source_homepage()
        navigator.source_clicks_submit_documents_on_homepage()
        navigator.source_continues_to_submit_page()

        # Then they are able to retrieve their codename from the UI
        source_codename = navigator.source_retrieves_codename_from_hint()
        assert source_codename

        # And they are able to close the codename hint UI
        content = navigator.driver.find_element_by_id("codename-show-checkbox")
        assert content.get_attribute("checked") is not None
        navigator.nav_helper.safe_click_by_id("codename-show")
        assert content.get_attribute("checked") is None

        # And on their second login
        navigator.source_logs_out()
        navigator.source_visits_source_homepage()
        navigator.source_chooses_to_login()
        navigator.source_proceeds_to_login(codename=source_codename)

        # The codename hint UI is no longer present
        codename = navigator.driver.find_elements_by_css_selector("#codename-reminder")
        assert len(codename) == 0