diff --git a/install_files/ansible-base/roles/build-securedrop-app-code-deb-pkg/files/usr.sbin.apache2 b/install_files/ansible-base/roles/build-securedrop-app-code-deb-pkg/files/usr.sbin.apache2 index b559e7a28a..9480b35afc 100644 --- a/install_files/ansible-base/roles/build-securedrop-app-code-deb-pkg/files/usr.sbin.apache2 +++ b/install_files/ansible-base/roles/build-securedrop-app-code-deb-pkg/files/usr.sbin.apache2 @@ -215,7 +215,7 @@ /var/www/securedrop/source_templates/index.html r, /var/www/securedrop/source_templates/locales.html r, /var/www/securedrop/source_templates/login.html r, - /var/www/securedrop/source_templates/logout_flashed_message.html r, + /var/www/securedrop/source_templates/logout.html r, /var/www/securedrop/source_templates/lookup.html r, /var/www/securedrop/source_templates/next_submission_flashed_message.html r, /var/www/securedrop/source_templates/notfound.html r, @@ -253,6 +253,7 @@ /var/www/securedrop/static/i/custom_logo.png rw, /var/www/securedrop/static/i/delete_gray.png r, /var/www/securedrop/static/i/delete_red.png r, + /var/www/securedrop/static/i/bang-stop.png r, /var/www/securedrop/static/i/favicon.png r, /var/www/securedrop/static/i/font-awesome/black/guard.svg r, /var/www/securedrop/static/i/font-awesome/black/times.svg r, @@ -290,6 +291,8 @@ /var/www/securedrop/static/i/tipbox/tipbox-hed-submit3.png r, /var/www/securedrop/static/i/tipbox/tipbox-hed-user.png r, /var/www/securedrop/static/i/tipbox/tipbox-logo.png r, + /var/www/securedrop/static/i/torbroom-black.png r, + /var/www/securedrop/static/i/torbroom-coral.png r, /var/www/securedrop/static/i/trash-x-out.png r, /var/www/securedrop/static/i/trash-x-solid.png r, /var/www/securedrop/static/i/un-star.png r, diff --git a/securedrop/sass/modules/_flash.sass b/securedrop/sass/modules/_flash.sass index a061b6e620..e75b78417a 100644 --- a/securedrop/sass/modules/_flash.sass +++ b/securedrop/sass/modules/_flash.sass @@ -4,8 +4,8 @@ flex-flow: row nowrap align-items: flex-start border-radius: 10px - padding: 10px margin: 10px + padding: 10px text-align: left font-size: medium @@ -38,11 +38,31 @@ i color: #D62727 + &.important-header + margin: auto 6px + color: $color_urgent_coral + &.important - border: 1px solid #EBDCEB - background: #FDFAFD + border-top: 1px solid #ece6e7 + border-left: 6px solid $color_urgent_coral + border-bottom: 1px solid $color_urgent_coral + border-right: 1px solid #ece6e7 + border-radius: 2px + margin-bottom: 30px + padding-left: 20px + padding-right: 8px + background-color: #FDFDFD + color: #383838 + align-items: center + + &:dir(rtl) + padding-left: 8px + padding-right: 20px + text-align: right + border-top: 1px solid #ece6e7 + border-left: 1px solid #ece6e7 + border-bottom: 1px solid $color_urgent_coral + border-right: 6px solid $color_urgent_coral - strong - color: #673466 p color: #555555 diff --git a/securedrop/source_app/main.py b/securedrop/source_app/main.py index c1748c0166..a7644c56e3 100644 --- a/securedrop/source_app/main.py +++ b/securedrop/source_app/main.py @@ -296,8 +296,12 @@ def login(): @view.route('/logout') def logout(): + """ + If a user is logged in, show them a logout page that prompts them to + click the New Identity button in Tor Browser to complete their session. + Otherwise redirect to the main Source Interface page. + """ if logged_in(): - msg = render_template('logout_flashed_message.html') # Clear the session after we render the message so it's localized # If a user specified a locale, save it and restore it @@ -305,7 +309,8 @@ def logout(): session.clear() session['locale'] = user_locale - flash(Markup(msg), "important hide-if-not-tor-browser") - return redirect(url_for('.index')) + return render_template('logout.html') + else: + return redirect(url_for('.index')) return view diff --git a/securedrop/source_templates/flashed.html b/securedrop/source_templates/flashed.html index 8b8cff4a17..e6cd25b20d 100644 --- a/securedrop/source_templates/flashed.html +++ b/securedrop/source_templates/flashed.html @@ -7,6 +7,8 @@ {% elif category == 'error' %} + {% elif category == 'important' %} + {% endif %} {{ message }} diff --git a/securedrop/source_templates/logout.html b/securedrop/source_templates/logout.html new file mode 100644 index 0000000000..3aa931ebef --- /dev/null +++ b/securedrop/source_templates/logout.html @@ -0,0 +1,8 @@ +{% extends "base.html" %} +{% block body %} + {{ gettext('LOG IN') }} + +
+

{{ gettext('One more thing...') }}

+

{{ gettext('Click the broom icon New Identity button in your Tor browser\'s toolbar. This will clear your Tor browser activity data on this device.').format(icon=url_for('static', filename='i/torbroom-black.png')) }}

+{% endblock %} diff --git a/securedrop/source_templates/logout_flashed_message.html b/securedrop/source_templates/logout_flashed_message.html deleted file mode 100644 index 3190d95486..0000000000 --- a/securedrop/source_templates/logout_flashed_message.html +++ /dev/null @@ -1,6 +0,0 @@ -
- -
-
{{ gettext('Important!') }}
-

{{ gettext('Thank you for exiting your session! Please select "New Identity" from the onion button in the Tor browser\'s toolbar to clear all history of your SecureDrop usage from this device.') }}

-
diff --git a/securedrop/source_templates/session_timeout.html b/securedrop/source_templates/session_timeout.html index f3b1fcbac7..802365f2f8 100644 --- a/securedrop/source_templates/session_timeout.html +++ b/securedrop/source_templates/session_timeout.html @@ -1,8 +1,6 @@ +
+ {{ gettext('Important') }} +
-
- -
-
{{ gettext('Important!') }}
-

{{ gettext('Your session timed out due to inactivity. Please login again if you want to continue using SecureDrop, or select "New Identity" from the onion button in the Tor browser\'s toolbar to clear all history of your SecureDrop usage from this device. If you are not using Tor Browser, restart your browser.') }}

-
+

{{ gettext('You were logged out due to inactivity. Click the broom icon New Identity button in your Tor browser\'s toolbar before moving on. This will clear your Tor browser activity data on this device.').format(icon=url_for('static', filename='i/torbroom-coral.png')) }}

diff --git a/securedrop/static/i/bang-stop.png b/securedrop/static/i/bang-stop.png new file mode 100644 index 0000000000..0a48359649 Binary files /dev/null and b/securedrop/static/i/bang-stop.png differ diff --git a/securedrop/static/i/torbroom-black.png b/securedrop/static/i/torbroom-black.png new file mode 100644 index 0000000000..11281b3caf Binary files /dev/null and b/securedrop/static/i/torbroom-black.png differ diff --git a/securedrop/static/i/torbroom-coral.png b/securedrop/static/i/torbroom-coral.png new file mode 100644 index 0000000000..de9fccbe08 Binary files /dev/null and b/securedrop/static/i/torbroom-coral.png differ diff --git a/securedrop/tests/functional/source_navigation_steps.py b/securedrop/tests/functional/source_navigation_steps.py index 3778c30dc0..dd19437fd9 100644 --- a/securedrop/tests/functional/source_navigation_steps.py +++ b/securedrop/tests/functional/source_navigation_steps.py @@ -19,6 +19,9 @@ def _is_on_lookup_page(self): def _is_on_generate_page(self): return self.wait_for(lambda: self.driver.find_element_by_id("create-form")) + def _is_on_logout_page(self): + return self.wait_for(lambda: self.driver.find_element_by_id("click-new-identity-tor")) + def _source_visits_source_homepage(self): self.driver.get(self.source_location) assert self._is_on_source_homepage() @@ -195,7 +198,7 @@ def reply_deleted(): def _source_logs_out(self): self.safe_click_by_id("logout") - self.wait_for(lambda: ("Submit for the first time" in self.driver.page_source)) + assert self._is_on_logout_page() def _source_not_found(self): self.driver.get(self.source_location + "/unlikely") @@ -218,7 +221,7 @@ def _source_sees_session_timeout_message(self): notification = self.driver.find_element_by_css_selector(".important") if not hasattr(self, "accept_languages"): - expected_text = "Your session timed out due to inactivity." + expected_text = "You were logged out due to inactivity." assert expected_text in notification.text def _source_sees_document_attachment_item(self): diff --git a/securedrop/tests/pageslayout/test_source.py b/securedrop/tests/pageslayout/test_source.py index 871c182253..0f66764296 100644 --- a/securedrop/tests/pageslayout/test_source.py +++ b/securedrop/tests/pageslayout/test_source.py @@ -153,11 +153,11 @@ def test_index(self): self._source_visits_source_homepage() self._screenshot('source-index.png') - def test_logout_flashed_message(self): + def test_logout(self): self.disable_js_torbrowser_driver() self._source_visits_source_homepage() self._source_chooses_to_submit_documents() self._source_continues_to_submit_page() self._source_submits_a_file() self._source_logs_out() - self._screenshot('source-logout_flashed_message.png') + self._screenshot('source-logout_page.png') diff --git a/securedrop/tests/test_source.py b/securedrop/tests/test_source.py index 5c1310cf13..fa6c4b1b56 100644 --- a/securedrop/tests/test_source.py +++ b/securedrop/tests/test_source.py @@ -251,7 +251,10 @@ def test_login_and_logout(source_app): assert 'logged_in' not in session assert 'codename' not in session text = resp.data.decode('utf-8') - assert 'Thank you for exiting your session!' in text + + # This is part of the logout page message instructing users + # to click the 'New Identity' icon + assert 'This will clear your Tor browser activity data' in text def test_user_must_log_in_for_protected_views(source_app): @@ -706,7 +709,7 @@ def test_source_session_expiration(config, source_app): assert not session text = resp.data.decode('utf-8') - assert 'Your session timed out due to inactivity' in text + assert 'You were logged out due to inactivity' in text def test_source_session_expiration_create(config, source_app): @@ -731,7 +734,7 @@ def test_source_session_expiration_create(config, source_app): assert not session text = resp.data.decode('utf-8') - assert 'Your session timed out due to inactivity' in text + assert 'You were logged out due to inactivity' in text def test_csrf_error_page(config, source_app): @@ -743,7 +746,7 @@ def test_csrf_error_page(config, source_app): resp = app.post(url_for('main.create'), follow_redirects=True) text = resp.data.decode('utf-8') - assert 'Your session timed out due to inactivity' in text + assert 'You were logged out due to inactivity' in text def test_source_can_only_delete_own_replies(source_app):