From 0acdd39a453dc73fc86ccc2d0394ef0e41802ca7 Mon Sep 17 00:00:00 2001 From: ro Date: Wed, 5 Feb 2020 09:46:41 -0500 Subject: [PATCH] - Add logout page and route that directs users to click the New Identity button in Tor browser to complete their session, if they were logged in, else redirectst to main source interface page. - Remove logout_flashed message since we redirect to a new page now. - Update functional tests to include _is_on_logout_page method and replace test_logout_flashed_message with test_logout screenshot in testsourcelayout - update flashed message graphic and add login button to successful logout page (may need button alignment tweak) - Include coral-theme broom graphic and move flash-notif styling to _flash.sass - update apparmor profile to include logout.html, new assets --- .../files/usr.sbin.apache2 | 5 ++- securedrop/sass/modules/_flash.sass | 30 +++++++++++++++--- securedrop/source_app/main.py | 11 +++++-- securedrop/source_templates/flashed.html | 2 ++ securedrop/source_templates/logout.html | 8 +++++ .../logout_flashed_message.html | 6 ---- .../source_templates/session_timeout.html | 10 +++--- securedrop/static/i/bang-stop.png | Bin 0 -> 637 bytes securedrop/static/i/torbroom-black.png | Bin 0 -> 1894 bytes securedrop/static/i/torbroom-coral.png | Bin 0 -> 1203 bytes .../functional/source_navigation_steps.py | 7 ++-- securedrop/tests/pageslayout/test_source.py | 4 +-- securedrop/tests/test_source.py | 11 ++++--- 13 files changed, 65 insertions(+), 29 deletions(-) create mode 100644 securedrop/source_templates/logout.html delete mode 100644 securedrop/source_templates/logout_flashed_message.html create mode 100644 securedrop/static/i/bang-stop.png create mode 100644 securedrop/static/i/torbroom-black.png create mode 100644 securedrop/static/i/torbroom-coral.png 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 0000000000000000000000000000000000000000..0a4835964912424786cd85008e62c9cca20aceea GIT binary patch literal 637 zcmV-@0)qXCP)Px%H%UZ6R9Fe^*+EjnAQS*lK1pxjqB{>!tLM;-?j431hb&-ONn^p2=!@2LR06Nc{!WqPY|u zD~Iw#JAqrn2A~_ktz$jWRp1ElKJgWHaDAK^a22NCF}#6du!7mZt_ppmx42jPnyr7zY+JfebO{q)UkPAjv} zd+6tIXyjb`MV%6CbbrFP|5wW3C0p{T@}<-rQK$jK5Lf;|E4Dm4k0d)81gQ z`zYCvCu@|;>2nw}GDW!%9h9c&3e{GrCObq$(n7ZkxkY*d4h#ve)g}Ro3J96 zjPRH{XS`m>;e_Rh@Bf)dkrC-4(yoz}#wxd8P2mPsvn96m zJwmZKPHluGz#8d}{$*eVBixFXcNXJp$-4i(d?Oeew~ltiqQwc^D%u0<1#SiHiABQ? XI|a?&0CEEv00000NkvXXu0mjfdhR3s literal 0 HcmV?d00001 diff --git a/securedrop/static/i/torbroom-black.png b/securedrop/static/i/torbroom-black.png new file mode 100644 index 0000000000000000000000000000000000000000..11281b3caf36574323624145f6ac26ccc7394f41 GIT binary patch literal 1894 zcmV-s2buVZP)kj1qOuyazC{yMJe^(YutmUk1@D~N@ zV2NzK*c#=l5(ya!EoVJ6_ z#ox2Cu-b{1v*Av&xFacH4rF=gLdKJUy~wo4qy0KauD58GNow(~rjT zU-aqNNe7+ULrO7rIyeJ3=Rjs3G(Hr=EhQVTgdeUmQ^85b>tP@>Z(9uc>1YgT1C6Bq zd9ARrHq^4YNfdkHFSm%Zy2)c_h5VKkmH1G{WoIw#ON zjO`}{7N@eulfJLrjRBcLUu!F5-|Bq+bNb610e^sQfjGKx8X7Y$SXXHUo_-_@zl+Y5>c=pUK30 zk<}2g*u_XOq&bAFn9W59c>WS&`o2iL8QZR7Uq-Gx>^7|HV89qmL;n?U2xCm*x~Brh zSvV#Dzca(gY@Hv#mKxd{u#yeD1ZT_jB#M3pYGxGD4O#}Z4lHu+lf-4dBQxfzb&Cs7 zpz{TfJ|}x5OMu6Nbe2MQ0W8((HafTjdmqAl=|r}^;P*z_SAvac@Vk+^o^FxvsZ^3N zJ`erPV1BXlAehfL$rqd_9ktL6@FEq(wkzt0d=i|L*_PE3{4+<@L#C<|(U;wg%*=9w zN$x%f3vp&!pEHf~VG8wnr=uNe`8ki5+0YB_Mh_;a{$4o{N51x1k0-$g&uu)mo$SR) zQMKaI`iH z%!W6V4O-M!=3end?}!>G6Z~pr?-K_xz#@WsQQy+L5Qe@dM!p?=fvM-2G7(@ zdoik~o54w1r{!ZuhrNG!c{N_-&%G8HkR&AdJ02(7LQd4!<&Y05AH$ICk&l9pidQL( zWNljoDHP8Hg7()IA`O6FJvK1=+zX@c<1JnyJ0!L4v4g}d6a&u(mfsfDkKb)1Sj8wPR(_^%;N zQ{NP>3+1W%BCTjZ=5eD;wCj$ux}KbYHc)5IWoqHI9)aev>7jz3Rw-A!?+TxY0&WBI zGuz&tu0A&@o52r*Qwm=ReBaO@GVvW1xQec#ThR|y^XrYz=zeffF(be{4(6H4#o!CU zw}YPn%NJmg4~{Pfk10(>^q0Xg$r5u(LbjZo10LTGCHScwdObYu_9Rv`5ih|`{+lK? zu}zLxe?oV1tb?jJ{@U^+xXe#Nz6s&kb;?BS0N(mq4_)KLb4?q#&VKAf@Uzv%{kZAs zxv0e)YgfrbzS=gxN$8H4|a;|p&v7vj>tT}b5Yg8rNB_T3xOxN zf+y;DhyDa+EWXMsQA**wYu12&1&0cCjcuuvWw-I8CjR2?;rQMhK<%U9N}h#tb3?in z?81a}Ot=ayg7G%+AK*|Nu3@Xer-74*6Cpnv>HxZMI$QwO<1z9O4J*|gZqm92TyHH8m#EwlK=n!07*qoM6N<$f(6fqLI3~& literal 0 HcmV?d00001 diff --git a/securedrop/static/i/torbroom-coral.png b/securedrop/static/i/torbroom-coral.png new file mode 100644 index 0000000000000000000000000000000000000000..de9fccbe08d60cccfea82886f53e775fa60b667b GIT binary patch literal 1203 zcmV;k1WfyhP)Px(ZAnByR9FeUS8He-RTMtwZW@9qKB%v>K3c@u3Q|hb)<>06&|hLvNkdzN{%EqB z&>(2A4-mIde;6x;irJ)5{G*5|nyURF8nHj5wPpkTC4@q0ePk0si`}$o9=pfy+|5j8 zc4l@rYjt4u-t+v1*ljq!)8bz`bE6cMHigUuwgl5+I222+hM zuExlMT^JmJ?E@bBQ8G16Jk)*K!z(+jDg%6cTaIF;72Z!+1m-bf(?@l&^I?dxu5}0A zAMp;z`u2OhI#p%BaUjoh*3+L?#);`5r;oku@V%p~i@!o7@67XffQNfuaOlVk$fma2 z!^hrNx{_xhD|h@w2H+@EI!1!C*~{skt|&h@B!FtcHK>XL z&@D+*`6g_)?Rb|F3u=c)VBJq54dA^QSRvDEQN6*dTQUIKXf9{>0R%-!bzZ}g^9sS$ zM`Qrf7~hUk>;mvT^I-ftEWQH|2ajw4U;BjrSpc{i2DYIzCf1VVk7CuEe4g2K(26Z7 zdk#P#o7)%D#O&)N+zG1CQ4Js9q2ADz?DORz+yGEWw_|mO0Net3utiJ$oCB`*e5!i_ z!(L?SW@IFxJd79ZxPTuco0B!@d>ybk4+n8~H9;r+(%AM;fL&(}An>f^3pEAgWf+Dg zGU(-U6neLo(M7fAzAp}fe@I=%XE;}|l~rYY1jGg@-w@zNGeU!a`XXz>l#ezIm*}@{ z!I2s~Xqc}cwMQTuD>C&3Ay4dCioUSk>InZ;q+6CW==CQ6)a(f&gA&ude;;ZBbs=|! zc$o_#zLl=e=vJM(56ZV8x+Pg|A3!y41@IDDarZ}jJUNYB(FRLByIq~qo_LaKc{!i% z`6EhCl1W1+GhgF6x1Z0ZhE>nqhVI28jgkxp7w989v{Vg)4|kOUxB4f?9z#Z-rrF#m z=v~SStWF+HET@^g-gs+OVeV1zR%ow5y7xFt&v=Py>sRxcBa8qYx2&UV<`R9@98dcreN& ziqAtmeO_6~3^s1_?F%F-|-Cq{RdO&j~x#K R4MhL|002ovPDHLkV1o0nK@R`` literal 0 HcmV?d00001 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):