Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add logout page that directs users to click New Identity button in Tor browser #5116

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
30 changes: 25 additions & 5 deletions securedrop/sass/modules/_flash.sass
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
eloquence marked this conversation as resolved.
Show resolved Hide resolved

&: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
eloquence marked this conversation as resolved.
Show resolved Hide resolved

strong
color: #673466
p
color: #555555
11 changes: 8 additions & 3 deletions securedrop/source_app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -296,16 +296,21 @@ 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
user_locale = g.locale
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
2 changes: 2 additions & 0 deletions securedrop/source_templates/flashed.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
<img src="{{ url_for('static', filename='i/font-awesome/info-circle-black.png') }}" width="20" height="16">
{% elif category == 'error' %}
<img class="pull-left" src="{{ url_for('static', filename='i/font-awesome/exclamation-triangle-black.png') }}" width="20" height="17">
{% elif category == 'important' %}
<img src="{{ url_for('static', filename='i/bang-stop.png') }}" width="22" height="22">
{% endif %}
{{ message }}
</div>
Expand Down
8 changes: 8 additions & 0 deletions securedrop/source_templates/logout.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{% extends "base.html" %}
{% block body %}
<a href="{{ url_for('main.login') }}" class="btn pull-right"> {{ gettext('LOG IN') }}
</a>
<br class="clearfix">
<h1>{{ gettext('One more thing...') }}</h1>
<p id="click-new-identity-tor"> {{ gettext('Click the <img src={icon} alt="broom icon" width="16" height="16">&nbsp;<strong>New Identity</strong> 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')) }}</p>
{% endblock %}
eloquence marked this conversation as resolved.
Show resolved Hide resolved
6 changes: 0 additions & 6 deletions securedrop/source_templates/logout_flashed_message.html

This file was deleted.

10 changes: 4 additions & 6 deletions securedrop/source_templates/session_timeout.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
<div class="flash important-header" dir="{{ g.text_direction }}">
<strong>{{ gettext('Important') }}</strong>
</div>
<div class="localized" dir="{{ g.text_direction }}">
<div class="icon">
<img src="{{ url_for('static', filename='i/hand_with_fingerprint.png') }}">
</div>
<div class="message"><strong>{{ gettext('Important!') }}</strong><br>
<p>{{ 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.') }}</p>
</div>
<p>{{ gettext('You were logged out due to inactivity. Click the <img src={icon} alt="broom icon" width="16" height="16">&nbsp;<strong>New Identity</strong> 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')) }}</p>
</div>
Binary file added securedrop/static/i/bang-stop.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added securedrop/static/i/torbroom-black.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added securedrop/static/i/torbroom-coral.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 5 additions & 2 deletions securedrop/tests/functional/source_navigation_steps.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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")
Expand All @@ -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):
Expand Down
4 changes: 2 additions & 2 deletions securedrop/tests/pageslayout/test_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')
11 changes: 7 additions & 4 deletions securedrop/tests/test_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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):
Expand All @@ -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):
Expand All @@ -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):
Expand Down