From a4109071a2313bfef7a061675ef60dd22a07a66b Mon Sep 17 00:00:00 2001 From: Cory Francis Myers Date: Wed, 30 Jun 2021 16:05:32 -0700 Subject: [PATCH 1/6] refactors for semantic markup reconciles JavaScript-free locale selector with ARIA best practices Accessible checkbox-based menus (e.g., hamburger menus[1]) tend to rely on JavaScript to update the menu's ARIA attributes in response to changes in state. Here we reconcile the script-free and accessibility requirements so that: 1. the current locale and "Choose locale" menu are announced logically; and 2. the menu itself is annotated to be announced by screen-reader and navigable by keyboard. As a bonus, each locale is now announced *in* that locale, via the A LANG and HREFLANG attributes. [1]: http://www.ashleysheridan.co.uk/blog/Making+an+Accessible+Hamburger+Menu first pass through "/generate" restore div#content and div#container first pass through "/lookup" pass 1.5 through /lookup with replies sets focus to #flashed when POST /submit redirects to /lookup As recommended by . first pass through "/logout" first pass through "/login" first pass through / first pass through ancillary templates --- securedrop/sass/modules/_menu.sass | 2 +- securedrop/sass/source.sass | 4 +- securedrop/source_app/forms.py | 35 +++++--- securedrop/source_app/main.py | 6 +- .../banner_warning_flashed.html | 5 +- securedrop/source_templates/base.html | 19 +++-- .../first_submission_flashed_message.html | 5 +- securedrop/source_templates/flashed.html | 10 ++- securedrop/source_templates/footer.html | 18 +++-- securedrop/source_templates/generate.html | 26 ++++-- securedrop/source_templates/index.html | 59 ++++++++------ securedrop/source_templates/locales.html | 29 ++++--- securedrop/source_templates/login.html | 15 ++-- securedrop/source_templates/logout.html | 5 +- securedrop/source_templates/lookup.html | 80 +++++++++++++------ .../next_submission_flashed_message.html | 2 + .../source_templates/session_timeout.html | 4 +- .../source_templates/why-public-key.html | 2 + .../functional/source_navigation_steps.py | 2 +- securedrop/tests/functional/test_source.py | 20 ++--- securedrop/tests/test_source.py | 4 +- 21 files changed, 228 insertions(+), 124 deletions(-) diff --git a/securedrop/sass/modules/_menu.sass b/securedrop/sass/modules/_menu.sass index 279613c671..b7a591d0b2 100644 --- a/securedrop/sass/modules/_menu.sass +++ b/securedrop/sass/modules/_menu.sass @@ -77,7 +77,7 @@ &:hover, &:focus, &:active background-color: #e8e8e8 -.menu__item a span +.menu__item a text-transform: capitalize .menu__checkbox:checked ~ .menu__items diff --git a/securedrop/sass/source.sass b/securedrop/sass/source.sass index b5906f15db..805c46d162 100644 --- a/securedrop/sass/source.sass +++ b/securedrop/sass/source.sass @@ -110,12 +110,14 @@ p#codename height: 0 overflow: hidden text-align: center + visibility: hidden &:target margin: auto padding: auto height: auto overflow: visible + visibility: visible .danger display: inline-block @@ -221,7 +223,7 @@ p#max-file-size font-style: italic margin-bottom: 0 -div.bubble +.bubble width: 415px position: absolute background-color: #ffffff diff --git a/securedrop/source_app/forms.py b/securedrop/source_app/forms.py index 75bd70bc35..6fb47b6329 100644 --- a/securedrop/source_app/forms.py +++ b/securedrop/source_app/forms.py @@ -11,21 +11,32 @@ class LoginForm(FlaskForm): - codename = PasswordField('codename', validators=[ - InputRequired(message=gettext('This field is required.')), - Length(1, PassphraseGenerator.MAX_PASSPHRASE_LENGTH, - message=gettext( - 'Field must be between 1 and ' - '{max_codename_len} characters long.'.format( - max_codename_len=PassphraseGenerator.MAX_PASSPHRASE_LENGTH))), - # Make sure to allow dashes since some words in the wordlist have them - Regexp(r'[\sA-Za-z0-9-]+$', message=gettext('Invalid input.')) - ]) + codename = PasswordField( + "codename", + validators=[ + InputRequired(message=gettext("This field is required.")), + Length( + 1, + PassphraseGenerator.MAX_PASSPHRASE_LENGTH, + message=gettext( + "Field must be between 1 and " + "{max_codename_len} characters long.".format( + max_codename_len=PassphraseGenerator.MAX_PASSPHRASE_LENGTH + ) + ), + ), + # Make sure to allow dashes since some words in the wordlist have them + Regexp(r"[\sA-Za-z0-9-]+$", message=gettext("Invalid input.")), + ], + ) class SubmissionForm(FlaskForm): - msg = TextAreaField("msg", render_kw={"placeholder": gettext("Write a message.")}) - fh = FileField("fh") + msg = TextAreaField("msg", + render_kw={"aria-label": gettext("Write a message."), + "placeholder": gettext("Write a message."), + }) + fh = FileField("fh", render_kw={"aria-label": gettext("Select a file to upload.")}) def validate_msg(self, field: wtforms.Field) -> None: if len(field.data) > Submission.MAX_MESSAGE_LEN: diff --git a/securedrop/source_app/main.py b/securedrop/source_app/main.py index 136df8e359..3d0b8cdec6 100644 --- a/securedrop/source_app/main.py +++ b/securedrop/source_app/main.py @@ -157,7 +157,7 @@ def submit() -> werkzeug.Response: for field, errors in form.errors.items(): for error in errors: flash(error, "error") - return redirect(url_for('main.lookup')) + return redirect(f"{url_for('main.lookup')}#flashed") msg = request.form['msg'] fh = None @@ -172,7 +172,7 @@ def submit() -> werkzeug.Response: "error") else: flash(gettext("You must enter a message."), "error") - return redirect(url_for('main.lookup')) + return redirect(f"{url_for('main.lookup')}#flashed") fnames = [] journalist_filename = g.source.journalist_filename @@ -235,7 +235,7 @@ def submit() -> werkzeug.Response: normalize_timestamps(g.filesystem_id) - return redirect(url_for('main.lookup')) + return redirect(f"{url_for('main.lookup')}#flashed") @view.route('/delete', methods=('POST',)) @login_required diff --git a/securedrop/source_templates/banner_warning_flashed.html b/securedrop/source_templates/banner_warning_flashed.html index 163a37577c..0c787709cb 100644 --- a/securedrop/source_templates/banner_warning_flashed.html +++ b/securedrop/source_templates/banner_warning_flashed.html @@ -1,7 +1,10 @@ {# these are flash messages that appear at the top and are really scary, like if you're using tor2web #} {% with messages = get_flashed_messages(with_categories=True, category_filter=["banner-warning"]) %} {% for category, message in messages %} -

{{ gettext('Warning') }} +

+ {# FIXME: + {{ gettext('Warning') }} + #} {{ message }}

{% endfor %} {% endwith %} diff --git a/securedrop/source_templates/base.html b/securedrop/source_templates/base.html index 5e60143155..43561c2279 100644 --- a/securedrop/source_templates/base.html +++ b/securedrop/source_templates/base.html @@ -18,33 +18,42 @@
+
{% block header %} - {% endblock %} +
-
+
{% if g.show_offline_message %} +

{{ gettext("We're sorry, our SecureDrop is currently offline.") }}

{{ gettext("Please try again later. Check our website for more information.") }}

+
{% else %} {% if 'logged_in' in session %} - {{ gettext('LOG OUT') }} + {% endif %} + {# FIXME: {% if not new_user%}
{% endif %} + #} {% endif %} {% block body %}{% endblock %} -
+
{% block footer %} diff --git a/securedrop/source_templates/first_submission_flashed_message.html b/securedrop/source_templates/first_submission_flashed_message.html index b2d131d355..e23796ce2c 100644 --- a/securedrop/source_templates/first_submission_flashed_message.html +++ b/securedrop/source_templates/first_submission_flashed_message.html @@ -1,5 +1,8 @@ +{# FIXME: {{ gettext('Success') }} -
{{ gettext('Success!') }} +#} +
+

{{ gettext('Success!') }}

{{ gettext('Thank you for sending this information to us. Please check back later for replies.') }} {{ gettext('Forgot your codename?') }} diff --git a/securedrop/source_templates/flashed.html b/securedrop/source_templates/flashed.html index b6fb74010d..d980d4b34a 100644 --- a/securedrop/source_templates/flashed.html +++ b/securedrop/source_templates/flashed.html @@ -1,8 +1,11 @@ {% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} +

{% endif %} {% endwith %} diff --git a/securedrop/source_templates/footer.html b/securedrop/source_templates/footer.html index ca7b8dda9c..9e42720788 100644 --- a/securedrop/source_templates/footer.html +++ b/securedrop/source_templates/footer.html @@ -1,12 +1,14 @@ -
- - - +

diff --git a/securedrop/source_templates/generate.html b/securedrop/source_templates/generate.html index e8e771d689..0b04efd181 100644 --- a/securedrop/source_templates/generate.html +++ b/securedrop/source_templates/generate.html @@ -3,34 +3,43 @@ {% block body %}

{{ gettext('Welcome') }}

- +{# FIXME: aside.center #} +

{{ gettext('Please either write this codename down and keep it in a safe place, or memorize it.') }}

-

{{ gettext('This codename is what you will use in future visits to receive messages from our team in response to what you submit on the next screen.') }}

+

{{ gettext('This codename is what you will use in future visits to receive messages from our team in response to what you submit on the next screen.') }}

+{# FIXME:
+#} -
+
+ {# FIXME: -

{{ codename }}

+ #} + + {{ codename }}
-
+
+{# FIXME: +

- +#}

{{ gettext('Because we do not track users of our SecureDrop service, in future visits, using this codename will be the only way we have to communicate with you should we have questions or are interested in additional information. Unlike passwords, there is no way to retrieve a lost codename.') }} @@ -40,6 +49,7 @@

{{ gettext('Welcome') }}

diff --git a/securedrop/source_templates/index.html b/securedrop/source_templates/index.html index d451e33baf..f5be14638d 100644 --- a/securedrop/source_templates/index.html +++ b/securedrop/source_templates/index.html @@ -17,9 +17,27 @@ {% endassets %} -
  {{ gettext('Your Tor Browser\'s Security Level is too low. Use the "Security Level"  button in your browser’s toolbar to change it.').format(icon=url_for("static", filename="i/font-awesome/white/guard.svg")) }}
-
{{ gettext('It is recommended to use Tor Browser to access SecureDrop: Learn how to install it, or ignore this warning to continue.').format(tor_browser_url=url_for('info.recommend_tor_browser')) }} {{ gettext('Close') }}
-
{{ gettext('It is recommended you use the desktop version of Tor Browser to access SecureDrop, as Orfox does not provide the same level of security and anonymity as the desktop version. Learn how to install it, or ignore this warning to continue.').format(tor_browser_url=url_for('info.recommend_tor_browser')) }} {{ gettext('Close') }}
+ + {# Warning bubble to help TB users disable JavaScript with NoScript. + Included here so the images can preload while the user is first + reading the page. Hidden by default. #} + + +
    +
  1. {{ gettext('Click the "Security Level" button in the toolbar above').format(icon=url_for("static", filename="i/font-awesome/black/guard.svg")) }}
  2. +
  3. {{ gettext('Select Advanced Security Settings') }}
  4. +
  5. {{ gettext('Select Safest') }}
  6. +
+

{{ gettext('Refresh this page, and you\'re done!') }}

+ +
+ + {% include 'banner_warning_flashed.html' %} @@ -29,31 +47,34 @@ {# The div `index-wrap` MUST be ordered this way so that the flexbox works on large and small screens See _source_index.sass for a more full understanding. #}
-
+
+

{{ g.organization_name }}

+ {# FIXME: {{ g.organization_name }} | {{ gettext('Logo Image') }} + #}
{% include 'locales.html' %}
-
+
-
-
-

+
+
+

{{ gettext('First submission') }}

{{ gettext('First time submitting to our SecureDrop? Start here.') }}

- +
-
+
-

+

{{ gettext('Return visit') }}

{{ gettext('Already have a codename? Check for replies or submit something new.') }}

@@ -63,24 +84,12 @@

{{ gettext('LOG IN') }}

-
+

{% include 'footer.html' %} - {# Warning bubble to help TB users disable JavaScript with NoScript. - Included here so the images can preload while the user is first - reading the page. Hidden by default. #} -
-
    -
  1. {{ gettext('Click the "Security Level" button in the toolbar above').format(icon=url_for("static", filename="i/font-awesome/black/guard.svg")) }}
  2. -
  3. {{ gettext('Select Advanced Security Settings') }}
  4. -
  5. {{ gettext('Select Safest') }}
  6. -
-

{{ gettext('Refresh this page, and you\'re done!') }}

- -
diff --git a/securedrop/source_templates/locales.html b/securedrop/source_templates/locales.html index ccf8d6c07e..ee1c6163e8 100644 --- a/securedrop/source_templates/locales.html +++ b/securedrop/source_templates/locales.html @@ -1,35 +1,42 @@ {% if g.locales|length > 1 %} - + {% endif %} diff --git a/securedrop/source_templates/login.html b/securedrop/source_templates/login.html index b3a703e61c..b12771b84b 100644 --- a/securedrop/source_templates/login.html +++ b/securedrop/source_templates/login.html @@ -8,21 +8,26 @@

{{ gettext('Enter Codename') }}

-

- {{ form.codename(id="login-with-existing-codename", class="codename-box", autocomplete="off", placeholder=gettext('Enter your codename'), autofocus=True) }} -
+

+ {{ form.codename(id='login-with-existing-codename', class='codename-box', autocomplete='off', placeholder=gettext('Enter your codename'), autofocus=True, **{'aria-label': gettext('Enter your codename'), 'aria-required': 'true', 'aria-describedby': 'flashed login-with-existing-code-name-errors', 'aria-invalid': 'true' if form.codename.errors else 'false'}) }} + {% if form.codename.errors %} + + {% endif %} +
diff --git a/securedrop/source_templates/logout.html b/securedrop/source_templates/logout.html index a928d4597f..2e4057b0c7 100644 --- a/securedrop/source_templates/logout.html +++ b/securedrop/source_templates/logout.html @@ -1,8 +1,9 @@ {% extends "base.html" %} {% block body %} - {{ gettext('LOG IN') }} - + {{ gettext('LOG IN') }} + {# FIXME:
+ #}

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

{{ gettext('Click the  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/lookup.html b/securedrop/source_templates/lookup.html index 00ae11b053..56fa2edd36 100644 --- a/securedrop/source_templates/lookup.html +++ b/securedrop/source_templates/lookup.html @@ -1,31 +1,42 @@ {% extends "base.html" %} -{% block body %} +{% block header %} +{{ super() }} {% if new_user %} -
+
- {{ gettext('Remember, your codename is:') }} - {{ gettext('Show') }} + {# FIXME: + + #} + +
- {{ gettext('Hide') }} -

{{ codename }}

+ + {{ codename }}
-
+ +{# FIXME:
+#} {% else %} -
+{# FIXME: +
+#} {% endif %} +{% endblock %} +{% block body %}
{% include 'flashed.html' %}
+
{% if allow_document_uploads %} -

{{ gettext('Submit Files or Messages') }}

+

{{ gettext('Submit Files or Messages') }}

{{ gettext('You can submit any kind of file, a message, or both.') }}

{% else %} -

{{ gettext('Submit Messages') }}

+

{{ gettext('Submit Messages') }}

{% endif %}

@@ -36,15 +47,19 @@

{{ gettext('Submit Messages') }}

{% endif %} {{ gettext('Learn more.').format(url=url_for('info.why_download_public_key')) }}

+{# FIXME:
+#}
{% if allow_document_uploads %}
+ {# FIXME: - {{ form.fh() }} + #} + {{ form.fh(**{"aria-describedby": "max-file-size"}) }}

{{ gettext('Maximum upload size: 500 MB') }}

{% endif %} @@ -53,7 +68,9 @@

{{ gettext('Submit Messages') }}

+ {# FIXME:
+ #}
+
+{# FIXME:
+#} -

{{ gettext('Read Replies') }}

+
+

{{ gettext('Read Replies') }}

{% if replies %} - + + {# FIXME:
+ #} {% for reply in replies %} -
- +
+ #} + {% endfor %}
{{ gettext('DELETE ALL REPLIES') }} -
-

{{ gettext('Are you finished with the replies?') }}

+ +

{{ gettext('Are you finished with the replies?') }}

{{ gettext('NO, NOT YET') }} -
+
{% else %} -

{{ gettext('— No Messages —') }}

+ {{ gettext('— No Messages —') }} {% endif %}
+
{% endblock %} diff --git a/securedrop/source_templates/next_submission_flashed_message.html b/securedrop/source_templates/next_submission_flashed_message.html index 2c68f80216..4c520f83b9 100644 --- a/securedrop/source_templates/next_submission_flashed_message.html +++ b/securedrop/source_templates/next_submission_flashed_message.html @@ -1,4 +1,6 @@ +{# FIXME: {{ gettext('Success') }} +#}

{{ html_contents }}

diff --git a/securedrop/source_templates/session_timeout.html b/securedrop/source_templates/session_timeout.html index 60377c2f87..0a721eea70 100644 --- a/securedrop/source_templates/session_timeout.html +++ b/securedrop/source_templates/session_timeout.html @@ -1,6 +1,6 @@ -
+

{{ gettext('Important') }} -

+

{{ gettext('You were logged out due to inactivity. Click the  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/source_templates/why-public-key.html b/securedrop/source_templates/why-public-key.html index 3aa1dc65d1..82820ba849 100644 --- a/securedrop/source_templates/why-public-key.html +++ b/securedrop/source_templates/why-public-key.html @@ -21,7 +21,9 @@

{{ gettext("Why download the team's public key?") }}

{{ gettext('Important: If you wish to remain anonymous, do not use GPG to sign the encrypted file (with the --sign or -s flag) as this will reveal your GPG identity to us.')|safe }}

+ {# FIXME: + #} {{ gettext('Back to submission page') }}

{% endblock %} diff --git a/securedrop/tests/functional/source_navigation_steps.py b/securedrop/tests/functional/source_navigation_steps.py index 9856541214..64b2459fcc 100644 --- a/securedrop/tests/functional/source_navigation_steps.py +++ b/securedrop/tests/functional/source_navigation_steps.py @@ -65,7 +65,7 @@ def _source_shows_codename(self, verify_source_name=True): self.wait_for(lambda: content.is_displayed()) assert content.is_displayed() - content_content = self.driver.find_element_by_css_selector("#codename-hint-content p") + content_content = self.driver.find_element_by_css_selector("#codename-hint-content output") if verify_source_name: assert content_content.text == self.source_name diff --git a/securedrop/tests/functional/test_source.py b/securedrop/tests/functional/test_source.py index 9b4f7e762e..d449e4326c 100644 --- a/securedrop/tests/functional/test_source.py +++ b/securedrop/tests/functional/test_source.py @@ -43,26 +43,26 @@ def test_lookup_codename_hint(self): class TestDownloadKey( - functional_test.FunctionalTest, - journalist_navigation_steps.JournalistNavigationStepsMixin): - + functional_test.FunctionalTest, + journalist_navigation_steps.JournalistNavigationStepsMixin, +): def test_journalist_key_from_source_interface(self): - data = self.return_downloaded_content(self.source_location + - "/public-key", None) + data = self.return_downloaded_content( + self.source_location + "/public-key", None + ) - data = data.decode('utf-8') + data = data.decode("utf-8") assert "BEGIN PGP PUBLIC KEY BLOCK" in data class TestDuplicateSourceInterface( - functional_test.FunctionalTest, - source_navigation_steps.SourceNavigationStepsMixin): - + functional_test.FunctionalTest, source_navigation_steps.SourceNavigationStepsMixin +): def get_codename_generate(self): return self.driver.find_element_by_css_selector("#codename").text def get_codename_lookup(self): - return self.driver.find_element_by_css_selector("#codename-hint-content p").text + return self.driver.find_element_by_css_selector("#codename-hint-content output").text def test_duplicate_generate_pages(self): # Test generation of multiple codenames in different browser tabs, ref. issue 4458. diff --git a/securedrop/tests/test_source.py b/securedrop/tests/test_source.py index b601a9c083..fd6e8dfb3f 100644 --- a/securedrop/tests/test_source.py +++ b/securedrop/tests/test_source.py @@ -101,8 +101,8 @@ def _find_codename(html): """Find a source codename (diceware passphrase) in HTML""" # Codenames may contain HTML escape characters, and the wordlist # contains various symbols. - codename_re = (r'

]*id="codename"[^>]*>' - r'(?P[a-z0-9 &#;?:=@_.*+()\'"$%!-]+)

') + codename_re = (r']*id="codename"[^>]*>' + r'(?P[a-z0-9 &#;?:=@_.*+()\'"$%!-]+)') codename_match = re.search(codename_re, html) assert codename_match is not None return codename_match.group('codename') From 850fad1a60f37d0c7a7ce4e43d0d81a397e705be Mon Sep 17 00:00:00 2001 From: Cory Francis Myers Date: Tue, 13 Jul 2021 14:44:30 -0700 Subject: [PATCH 2/6] corrects semantic markup per validators and accessibility-audit tools second pass through /: validate/audit second pass through /lookup: validate/audit second pass through /login: validate/audit second pass through ancillary templates: validate/audit --- .../source_templates/banner_warning_flashed.html | 2 +- .../first_submission_flashed_message.html | 2 +- securedrop/source_templates/index.html | 5 ++++- securedrop/source_templates/locales.html | 6 +++--- securedrop/source_templates/login.html | 6 +++++- securedrop/source_templates/lookup.html | 15 ++++++++++----- .../next_submission_flashed_message.html | 4 ++-- securedrop/source_templates/use-tor-browser.html | 7 +++---- 8 files changed, 29 insertions(+), 18 deletions(-) diff --git a/securedrop/source_templates/banner_warning_flashed.html b/securedrop/source_templates/banner_warning_flashed.html index 0c787709cb..9c6dcf28ef 100644 --- a/securedrop/source_templates/banner_warning_flashed.html +++ b/securedrop/source_templates/banner_warning_flashed.html @@ -1,7 +1,7 @@ {# these are flash messages that appear at the top and are really scary, like if you're using tor2web #} {% with messages = get_flashed_messages(with_categories=True, category_filter=["banner-warning"]) %} {% for category, message in messages %} -

+

{{ gettext('Success!') }}

{{ gettext('Forgot your codename?') }}

- + diff --git a/securedrop/source_templates/index.html b/securedrop/source_templates/index.html index f5be14638d..b8692bdd8c 100644 --- a/securedrop/source_templates/index.html +++ b/securedrop/source_templates/index.html @@ -26,7 +26,7 @@ {# Warning bubble to help TB users disable JavaScript with NoScript. Included here so the images can preload while the user is first reading the page. Hidden by default. #} - +
  1. {{ gettext('Click the "Security Level" button in the toolbar above').format(icon=url_for("static", filename="i/font-awesome/black/guard.svg")) }}
  2. @@ -42,6 +42,7 @@
{% else %} - {{ gettext('— No Messages —') }} + {{ gettext('No Messages') }} {% endif %} diff --git a/securedrop/source_templates/next_submission_flashed_message.html b/securedrop/source_templates/next_submission_flashed_message.html index 86cc08f054..e2cdf975cb 100644 --- a/securedrop/source_templates/next_submission_flashed_message.html +++ b/securedrop/source_templates/next_submission_flashed_message.html @@ -1,6 +1,3 @@ -{# FIXME: -{{ gettext('Success') }} -#}

{{ html_contents }}

diff --git a/securedrop/source_templates/why-public-key.html b/securedrop/source_templates/why-public-key.html index 82820ba849..8b3df3dee0 100644 --- a/securedrop/source_templates/why-public-key.html +++ b/securedrop/source_templates/why-public-key.html @@ -21,9 +21,6 @@

{{ gettext("Why download the team's public key?") }}

{{ gettext('Important: If you wish to remain anonymous, do not use GPG to sign the encrypted file (with the --sign or -s flag) as this will reveal your GPG identity to us.')|safe }}

- {# FIXME: - - #} - {{ gettext('Back to submission page') }} + {{ gettext('Back to submission page') }}

{% endblock %} From 700adab63a0b50c8ebef7a95bc3ee87a6dfb051e Mon Sep 17 00:00:00 2001 From: Cory Francis Myers Date: Sun, 18 Jul 2021 20:43:19 -0700 Subject: [PATCH 4/6] replaces and removes STRONG elements according to new HTML5 semantics Replaces STRONG elements with B, according to the latter's new HTML5 semantics[1]. Removes STRONG elements in headings, where they are superfluous both semantically and visually. [1]: https://html.spec.whatwg.org/multipage/text-level-semantics.html#the-b-element --- securedrop/source_templates/footer.html | 2 +- securedrop/source_templates/generate.html | 2 +- securedrop/source_templates/index.html | 6 +++--- securedrop/source_templates/logout.html | 2 +- securedrop/source_templates/lookup.html | 2 +- securedrop/source_templates/session_timeout.html | 4 ++-- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/securedrop/source_templates/footer.html b/securedrop/source_templates/footer.html index 4d05614bc0..abeb092b42 100644 --- a/securedrop/source_templates/footer.html +++ b/securedrop/source_templates/footer.html @@ -1,6 +1,6 @@

{{ gettext('Welcome') }}

-

{{ gettext('Because we do not track users of our SecureDrop +

{{ gettext('Because we do not track users of our SecureDrop service, in future visits, using this codename will be the only way we have to communicate with you should we have questions or are interested in additional information. Unlike passwords, there is no way to retrieve a lost codename.') }}

diff --git a/securedrop/source_templates/index.html b/securedrop/source_templates/index.html index 3e3476bc4c..fd3bd2038a 100644 --- a/securedrop/source_templates/index.html +++ b/securedrop/source_templates/index.html @@ -18,7 +18,7 @@ {# Warning bubble to help TB users disable JavaScript with NoScript. Included here so the images can preload while the user is first @@ -27,8 +27,8 @@
  1. {{ gettext('Click the "Security Level" button in the toolbar above').format(icon=url_for("static", filename="i/font-awesome/black/guard.svg")) }}
  2. -
  3. {{ gettext('Select Advanced Security Settings') }}
  4. -
  5. {{ gettext('Select Safest') }}
  6. +
  7. {{ gettext('Select Advanced Security Settings') }}
  8. +
  9. {{ gettext('Select Safest') }}

{{ gettext('Refresh this page, and you\'re done!') }}

diff --git a/securedrop/source_templates/logout.html b/securedrop/source_templates/logout.html index e229b578c9..dcdf020716 100644 --- a/securedrop/source_templates/logout.html +++ b/securedrop/source_templates/logout.html @@ -5,6 +5,6 @@

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

-

{{ gettext('Click the  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')) }}

+

{{ gettext('Click the  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/lookup.html b/securedrop/source_templates/lookup.html index 3416acf176..6bc27de258 100644 --- a/securedrop/source_templates/lookup.html +++ b/securedrop/source_templates/lookup.html @@ -99,7 +99,7 @@

- {{ gettext('Important') }} + {{ gettext('Important') }}

-

{{ gettext('You were logged out due to inactivity. Click the  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')) }}

+

{{ gettext('You were logged out due to inactivity. Click the  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')) }}

From 7d26aaab6757717adbcb7ad7fe7eb38f929c4c95 Mon Sep 17 00:00:00 2001 From: Cory Francis Myers Date: Tue, 27 Jul 2021 11:25:38 -0700 Subject: [PATCH 5/6] addresses review feedback addresses review feedback Corrects 876bfa2's removal of these decorative IMGs without replacing their semantic content. thread: https://github.com/freedomofpress/securedrop/pull/6041#discussion_r673875533 squash/fixup: 876bfa23fa540b0fcd1b72a669851929591cdffd addresses review feedback Adds explicit title-case ARIA-LABEL attributes to elements whose strings are in all caps to support idiomatic translation (cf. #5821, #6003). thread: https://github.com/freedomofpress/securedrop/pull/6041#discussion_r673878829 addresses review feedback Refactors MAIN.index-row rather than wrapping the whole DIV.grid in MAIN. thread: https://github.com/freedomofpress/securedrop/pull/6041#discussion_r673896426 squash/fixup: 80547cdc12721a91605e76331277d0db80d5e1ab removes stray ARIA-LABELS (per review feedback) thread: https://github.com/freedomofpress/securedrop/pull/6041#discussion_r673900985 addresses review feedback LABEL[for="codename"] was marked HIDDEN to prevent redundant narration in screen readers. Refactoring the LABEL to an H2 that ARIA-labels the containing section streamlines the narration and makes for a more-logical outline. thread: https://github.com/freedomofpress/securedrop/pull/6041#discussion_r674255604 squash/fixup: ae56f49245c1b83cc284fc37204a3557495487d1 refactors SECTION#codename-hint as DETAILS (per review feedback) ::{before,after} pseudo-elements must be used to style the expand/collapse links ("Show"/"Hide", respectively) because under DIR="ltr" the ::marker pseudo-element will be displayed to the left of the SUMMARY. thread: https://github.com/freedomofpress/securedrop/pull/6041#discussion_r674263579 squash/fixup: 1f6964061a1e434077ef7509189713aa18a70c20 adds "button" role to non-navigating links (per review feedback) thread: https://github.com/freedomofpress/securedrop/pull/6041#discussion_r674289745 undoes autoformatting squash/fixup: 1f6964061a1e434077ef7509189713aa18a70c20 fixes tests for refactored DETAILS#codename-hint squash/fixup: c8baf3d1491d6e7952ab98e4e62dc2f6d58dc862 fixes unclosed ARIA-LABEL attribute (per review feedback) thread: https://github.com/freedomofpress/securedrop/pull/6041#discussion_r683734312 squash/fixup: d6116a2740109d8728ff5c38b0fe30bb9b72bb86 refactors TIME as H3 of reply ARTICLE (per review feedback) Each reply now consists of an ARTICLE automatically labeled by its H3 TIME. These implicit ARIA semantics are more fluent than those marked explicitly in 1f696406. thread: https://github.com/freedomofpress/securedrop/pull/6041#discussion_r683735790 squash/fixup: 1f6964061a1e434077ef7509189713aa18a70c20 refactors OUTPUTs as MARKs or Ps (per review feedback) Some "browser / screen reader pairings may not announce or make available the accessible name of the output, even though its a labelable element"[1], apparently including Orca (i.e., on Tails). These elements give the next-best semantics without implying a live region. [1]: https://www.scottohara.me/blog/2019/07/10/the-output-element.html thread: https://github.com/freedomofpress/securedrop/pull/6041#pullrequestreview-723661645 squash/fixup: 1f6964061a1e434077ef7509189713aa18a70c20 squash/fixup: f37fc17e19e83400dccfc612e88d065f1ad1a9a7 squash/fixup: ae56f49245c1b83cc284fc37204a3557495487d1 --- securedrop/sass/source.sass | 50 +++++++++---------- securedrop/source_app/forms.py | 34 +++++-------- securedrop/source_templates/base.html | 2 +- .../first_submission_flashed_message.html | 2 +- securedrop/source_templates/flashed.html | 2 +- securedrop/source_templates/generate.html | 8 +-- securedrop/source_templates/index.html | 14 +++--- securedrop/source_templates/login.html | 4 +- securedrop/source_templates/logout.html | 2 +- securedrop/source_templates/lookup.html | 43 ++++++---------- .../functional/source_navigation_steps.py | 24 +++++---- securedrop/tests/functional/test_source.py | 20 ++++---- securedrop/tests/test_source.py | 4 +- 13 files changed, 93 insertions(+), 116 deletions(-) diff --git a/securedrop/sass/source.sass b/securedrop/sass/source.sass index d3a0ee331c..c2c4b25b5f 100644 --- a/securedrop/sass/source.sass +++ b/securedrop/sass/source.sass @@ -34,37 +34,33 @@ text-align: center width: 80% -@media only screen and (max-width: 880px) +@media only screen #codename-hint - width: 100% + summary + cursor: pointer -#codename-hint-visible - .visible-codename - margin: auto - padding: auto - height: auto - overflow: visible + &:after + content: "Show" + display: block + float: right - .hidden-codename - margin: 0 - padding: 0 - height: 0 - overflow: hidden + text-decoration: none + color: $color_securedrop_blue + border-bottom: 1px solid rgba(0, 117, 247, 0.4) - &:target + &:hover, &:active + &:after + color: $color_grimace_blue + border-bottom: 1px solid rgba(42, 49, 157, 1) - .visible-codename - margin: 0 - padding: 0 - height: 0 - overflow: hidden - border: 0 + &[open] + summary + &:after + content: "Hide" - .hidden-codename - margin: auto - padding: auto - height: auto - overflow: visible +@media only screen and (max-width: 880px) + #codename-hint + width: 100% input.codename-box width: 100% @@ -72,6 +68,7 @@ input.codename-box font-weight: bold .codename + background-color: transparent font-family: monospace letter-spacing: 0.15em font-weight: normal @@ -160,6 +157,7 @@ p#codename font-size: 10px font-weight: bold padding: 5px + margin: 0 a.delete float: right @@ -217,7 +215,7 @@ p#codename margin: 0 2% padding: 5px 15px - output#no-replies + #no-replies display: block font-weight: bold text-align: center diff --git a/securedrop/source_app/forms.py b/securedrop/source_app/forms.py index 6fb47b6329..90701dc035 100644 --- a/securedrop/source_app/forms.py +++ b/securedrop/source_app/forms.py @@ -11,31 +11,21 @@ class LoginForm(FlaskForm): - codename = PasswordField( - "codename", - validators=[ - InputRequired(message=gettext("This field is required.")), - Length( - 1, - PassphraseGenerator.MAX_PASSPHRASE_LENGTH, - message=gettext( - "Field must be between 1 and " - "{max_codename_len} characters long.".format( - max_codename_len=PassphraseGenerator.MAX_PASSPHRASE_LENGTH - ) - ), - ), - # Make sure to allow dashes since some words in the wordlist have them - Regexp(r"[\sA-Za-z0-9-]+$", message=gettext("Invalid input.")), - ], - ) + codename = PasswordField('codename', validators=[ + InputRequired(message=gettext('This field is required.')), + Length(1, PassphraseGenerator.MAX_PASSPHRASE_LENGTH, + message=gettext( + 'Field must be between 1 and ' + '{max_codename_len} characters long.'.format( + max_codename_len=PassphraseGenerator.MAX_PASSPHRASE_LENGTH))), + # Make sure to allow dashes since some words in the wordlist have them + Regexp(r'[\sA-Za-z0-9-]+$', message=gettext('Invalid input.')) + ]) class SubmissionForm(FlaskForm): - msg = TextAreaField("msg", - render_kw={"aria-label": gettext("Write a message."), - "placeholder": gettext("Write a message."), - }) + msg = TextAreaField("msg", render_kw={"placeholder": gettext("Write a message."), + "aria-label": gettext("Write a message.")}) fh = FileField("fh", render_kw={"aria-label": gettext("Select a file to upload.")}) def validate_msg(self, field: wtforms.Field) -> None: diff --git a/securedrop/source_templates/base.html b/securedrop/source_templates/base.html index f309e4514d..bfb75f8115 100644 --- a/securedrop/source_templates/base.html +++ b/securedrop/source_templates/base.html @@ -37,7 +37,7 @@

{{ gettext("We're sorry, our SecureDrop is currently offline.") }}

{% if 'logged_in' in session %} {% endif %} diff --git a/securedrop/source_templates/first_submission_flashed_message.html b/securedrop/source_templates/first_submission_flashed_message.html index 53926883cd..629e47db72 100644 --- a/securedrop/source_templates/first_submission_flashed_message.html +++ b/securedrop/source_templates/first_submission_flashed_message.html @@ -1,7 +1,7 @@

{{ gettext('Success!') }}

{{ gettext('Thank you for sending this information to us. Please check back later for replies.') }} - + {{ gettext('Forgot your codename?') }}

diff --git a/securedrop/source_templates/flashed.html b/securedrop/source_templates/flashed.html index deeabfe20b..2ff82ac231 100644 --- a/securedrop/source_templates/flashed.html +++ b/securedrop/source_templates/flashed.html @@ -4,7 +4,7 @@
    {% for category, message in messages %} {% if category != 'banner-warning' %} -
  • +
  • {{ message }}
  • {% endif %} diff --git a/securedrop/source_templates/generate.html b/securedrop/source_templates/generate.html index 310f39f12a..fcf8055e90 100644 --- a/securedrop/source_templates/generate.html +++ b/securedrop/source_templates/generate.html @@ -7,9 +7,9 @@

    {{ gettext('Welcome') }}

    {{ gettext('This codename is what you will use in future visits to receive messages from our team in response to what you submit on the next screen.') }}

    -
    - - {{ codename }} +
    +

    {{ gettext('Codename') }}

    + {{ codename }}
    @@ -28,7 +28,7 @@

    {{ gettext('Welcome') }}

    -
    diff --git a/securedrop/source_templates/index.html b/securedrop/source_templates/index.html index fd3bd2038a..d0999e1524 100644 --- a/securedrop/source_templates/index.html +++ b/securedrop/source_templates/index.html @@ -39,7 +39,6 @@
    - diff --git a/securedrop/source_templates/login.html b/securedrop/source_templates/login.html index c758e40500..7f6b6d7907 100644 --- a/securedrop/source_templates/login.html +++ b/securedrop/source_templates/login.html @@ -24,10 +24,10 @@

    {{ gettext('Enter Codename') }}

    - - + {{ gettext('CANCEL') }}
    diff --git a/securedrop/source_templates/logout.html b/securedrop/source_templates/logout.html index dcdf020716..5fcab4f7e0 100644 --- a/securedrop/source_templates/logout.html +++ b/securedrop/source_templates/logout.html @@ -1,7 +1,7 @@ {% extends "base.html" %} {% block body %}

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

    diff --git a/securedrop/source_templates/lookup.html b/securedrop/source_templates/lookup.html index 6bc27de258..614db14a56 100644 --- a/securedrop/source_templates/lookup.html +++ b/securedrop/source_templates/lookup.html @@ -2,21 +2,10 @@ {% block body %} {% if new_user %} -
    -
    - - {# ARIA-HIDDEN violates axe rule aria-hidden-focus, because we (a) want to - hide the superfluous "show"/"hide" links from screen-readers, (b) do not - want to remove these elements from sequential navigation with TABINDEX="-1", - and (c) do not have recourse in the Source Interface to scripting the - ARIA-HIDDEN value dynamically. Cf. #6031. #} - -
    - - {{ codename }} -
    -
    -
    +
    + {{ gettext('Remember, your codename is:') }} + {{ codename }} +
    {% endif %}
    @@ -54,13 +43,13 @@

    {{ gettext('Submit Messages') }}

    - - + {{ gettext('CANCEL') }}
    @@ -72,23 +61,23 @@

    {{ gettext('Read Replies') }}

    {% if replies %} - +

    {{ gettext("You have received a reply. To protect your identity in the unlikely event someone learns your codename, please delete all replies when you're done with them. This also lets us know that you are aware of our reply. You can respond by submitting new files and messages above.") }} - +

    {% for reply in replies %} -
    - + {% endfor %}
    - {{ gettext('DELETE ALL REPLIES') }} + {{ gettext('DELETE ALL REPLIES') }}

    {{ gettext('Are you finished with the replies?') }}

    - {{ gettext('NO, NOT YET') }} + {{ gettext('NO, NOT YET') }}
    {% else %} - {{ gettext('No Messages') }} +

    {{ gettext('No Messages') }}

    {% endif %}
    diff --git a/securedrop/tests/functional/source_navigation_steps.py b/securedrop/tests/functional/source_navigation_steps.py index 64b2459fcc..ebf33bd6db 100644 --- a/securedrop/tests/functional/source_navigation_steps.py +++ b/securedrop/tests/functional/source_navigation_steps.py @@ -58,25 +58,27 @@ def _source_chooses_to_submit_documents(self): self.source_name = codename.text def _source_shows_codename(self, verify_source_name=True): - content = self.driver.find_element_by_id("codename-hint-content") - assert not content.is_displayed() + # The DETAILS element will be missing the OPEN attribute if it is + # closed, hiding its contents. + content = self.driver.find_element_by_css_selector("details#codename-hint") + assert content.get_attribute("open") is None - self.safe_click_by_id("codename-hint-show") + self.safe_click_by_id("codename-hint") - self.wait_for(lambda: content.is_displayed()) - assert content.is_displayed() - content_content = self.driver.find_element_by_css_selector("#codename-hint-content output") + assert content.get_attribute("open") is not None + content_content = self.driver.find_element_by_css_selector("details#codename-hint mark") if verify_source_name: assert content_content.text == self.source_name def _source_hides_codename(self): - content = self.driver.find_element_by_id("codename-hint-content") - assert content.is_displayed() + # The DETAILS element will have the OPEN attribute if it is open, + # displaying its contents. + content = self.driver.find_element_by_css_selector("details#codename-hint") + assert content.get_attribute("open") is not None - self.safe_click_by_id("codename-hint-hide") + self.safe_click_by_id("codename-hint") - self.wait_for(lambda: not content.is_displayed()) - assert not content.is_displayed() + assert content.get_attribute("open") is None def _source_sees_no_codename(self): codename = self.driver.find_elements_by_css_selector(".code-reminder") diff --git a/securedrop/tests/functional/test_source.py b/securedrop/tests/functional/test_source.py index d449e4326c..a1f2387163 100644 --- a/securedrop/tests/functional/test_source.py +++ b/securedrop/tests/functional/test_source.py @@ -43,26 +43,26 @@ def test_lookup_codename_hint(self): class TestDownloadKey( - functional_test.FunctionalTest, - journalist_navigation_steps.JournalistNavigationStepsMixin, -): + functional_test.FunctionalTest, + journalist_navigation_steps.JournalistNavigationStepsMixin): + def test_journalist_key_from_source_interface(self): - data = self.return_downloaded_content( - self.source_location + "/public-key", None - ) + data = self.return_downloaded_content(self.source_location + + "/public-key", None) - data = data.decode("utf-8") + data = data.decode('utf-8') assert "BEGIN PGP PUBLIC KEY BLOCK" in data class TestDuplicateSourceInterface( - functional_test.FunctionalTest, source_navigation_steps.SourceNavigationStepsMixin -): + functional_test.FunctionalTest, + source_navigation_steps.SourceNavigationStepsMixin): + def get_codename_generate(self): return self.driver.find_element_by_css_selector("#codename").text def get_codename_lookup(self): - return self.driver.find_element_by_css_selector("#codename-hint-content output").text + return self.driver.find_element_by_css_selector("#codename-hint mark").text def test_duplicate_generate_pages(self): # Test generation of multiple codenames in different browser tabs, ref. issue 4458. diff --git a/securedrop/tests/test_source.py b/securedrop/tests/test_source.py index fd6e8dfb3f..588535067d 100644 --- a/securedrop/tests/test_source.py +++ b/securedrop/tests/test_source.py @@ -101,8 +101,8 @@ def _find_codename(html): """Find a source codename (diceware passphrase) in HTML""" # Codenames may contain HTML escape characters, and the wordlist # contains various symbols. - codename_re = (r']*id="codename"[^>]*>' - r'(?P[a-z0-9 &#;?:=@_.*+()\'"$%!-]+)') + codename_re = (r']*id="codename"[^>]*>' + r'(?P[a-z0-9 &#;?:=@_.*+()\'"$%!-]+)') codename_match = re.search(codename_re, html) assert codename_match is not None return codename_match.group('codename') From 8f2b5031f9ae1f55586a7eeab52cf4503538ee02 Mon Sep 17 00:00:00 2001 From: Cory Francis Myers Date: Mon, 9 Aug 2021 14:04:49 -0400 Subject: [PATCH 6/6] formats templates for more-consistent indentation A refactoring like #5986 seems like a good opportunity for this kind of reformatting. --- .../banner_warning_flashed.html | 11 +- securedrop/source_templates/base.html | 93 ++++++----- securedrop/source_templates/error.html | 2 +- .../first_submission_flashed_message.html | 4 +- securedrop/source_templates/flashed.html | 12 +- securedrop/source_templates/footer.html | 2 +- securedrop/source_templates/generate.html | 20 ++- securedrop/source_templates/index.html | 157 ++++++++++-------- securedrop/source_templates/locales.html | 38 +++-- securedrop/source_templates/login.html | 40 ++--- securedrop/source_templates/logout.html | 17 +- securedrop/source_templates/lookup.html | 131 ++++++++------- .../next_submission_flashed_message.html | 2 +- securedrop/source_templates/notfound.html | 2 +- .../source_templates/session_timeout.html | 6 +- .../source_templates/tor2web-warning.html | 8 +- .../source_templates/use-tor-browser.html | 11 +- .../source_templates/why-public-key.html | 35 ++-- 18 files changed, 326 insertions(+), 265 deletions(-) diff --git a/securedrop/source_templates/banner_warning_flashed.html b/securedrop/source_templates/banner_warning_flashed.html index ed1a0b364e..01350b2953 100644 --- a/securedrop/source_templates/banner_warning_flashed.html +++ b/securedrop/source_templates/banner_warning_flashed.html @@ -1,7 +1,8 @@ {# these are flash messages that appear at the top and are really scary, like if you're using tor2web #} {% with messages = get_flashed_messages(with_categories=True, category_filter=["banner-warning"]) %} - {% for category, message in messages %} - - {% endfor %} -{% endwith %} +{% for category, message in messages %} + +{% endfor %} +{% endwith %} \ No newline at end of file diff --git a/securedrop/source_templates/base.html b/securedrop/source_templates/base.html index bfb75f8115..921c00bdf8 100644 --- a/securedrop/source_templates/base.html +++ b/securedrop/source_templates/base.html @@ -1,55 +1,60 @@ - - - - {% if g.organization_name == "SecureDrop" %} - {{ g.organization_name }} | {{ gettext('Protecting Journalists and Sources') }} - {% else %} - {{ g.organization_name }} | {{ gettext('SecureDrop') }} - {% endif %} - - - - {% block extrahead %}{% endblock %} - - - {% include 'banner_warning_flashed.html' %} - -
    -
    -
    + + + + + {% if g.organization_name == "SecureDrop" %} + {{ g.organization_name }} | {{ gettext('Protecting Journalists and Sources') }} + {% else %} + {{ g.organization_name }} | {{ gettext('SecureDrop') }} + {% endif %} + + + + {% block extrahead %}{% endblock %} + + + + {% include 'banner_warning_flashed.html' %} + +
    +
    +
    {% block header %} - - - - {% include 'locales.html' %} + + + + {% include 'locales.html' %} {% endblock %} -
    +
    -
    - {% if g.show_offline_message %} -
    +
    + {% if g.show_offline_message %} +

    {{ gettext("We're sorry, our SecureDrop is currently offline.") }}

    {{ gettext("Please try again later. Check our website for more information.") }}

    -
    - {% else %} +
    + {% else %} - {% if 'logged_in' in session %} - - {% endif %} + {% if 'logged_in' in session %} + + {% endif %} - {% endif %} + {% endif %} - {% block body %}{% endblock %} -
    -
    - - {% block footer %} - {% include 'footer.html' %} - {% endblock %} + {% block body %}{% endblock %} +
    - - + + {% block footer %} + {% include 'footer.html' %} + {% endblock %} + + + + \ No newline at end of file diff --git a/securedrop/source_templates/error.html b/securedrop/source_templates/error.html index fa83ed90bd..5a0e6c46c8 100644 --- a/securedrop/source_templates/error.html +++ b/securedrop/source_templates/error.html @@ -5,4 +5,4 @@

    {{ gettext('Server error') }}

    {{ gettext('Sorry, the website encountered an error and was unable to complete your request.') }}

    {{ gettext('Look up a codename...') }}

    -{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/securedrop/source_templates/first_submission_flashed_message.html b/securedrop/source_templates/first_submission_flashed_message.html index 629e47db72..088a07f7b4 100644 --- a/securedrop/source_templates/first_submission_flashed_message.html +++ b/securedrop/source_templates/first_submission_flashed_message.html @@ -2,7 +2,7 @@

    {{ gettext('Success!') }}

    {{ gettext('Thank you for sending this information to us. Please check back later for replies.') }} - {{ gettext('Forgot your codename?') }} + {{ gettext('Forgot your codename?') }}

    -
    +
    \ No newline at end of file diff --git a/securedrop/source_templates/flashed.html b/securedrop/source_templates/flashed.html index 2ff82ac231..ec6db8026e 100644 --- a/securedrop/source_templates/flashed.html +++ b/securedrop/source_templates/flashed.html @@ -2,14 +2,14 @@ {% if messages %} {% endif %} -{% endwith %} +{% endwith %} \ No newline at end of file diff --git a/securedrop/source_templates/footer.html b/securedrop/source_templates/footer.html index abeb092b42..a91cfe7ea9 100644 --- a/securedrop/source_templates/footer.html +++ b/securedrop/source_templates/footer.html @@ -8,4 +8,4 @@ -
+ \ No newline at end of file diff --git a/securedrop/source_templates/generate.html b/securedrop/source_templates/generate.html index fcf8055e90..2fe2e30e9f 100644 --- a/securedrop/source_templates/generate.html +++ b/securedrop/source_templates/generate.html @@ -3,13 +3,17 @@ {% block body %}

{{ gettext('Welcome') }}

-

{{ gettext('Please either write this codename down and keep it in a safe place, or memorize it.') }}

+

+ {{ gettext('Please either write this codename down and keep it in a safe place, or memorize it.') }}

-

{{ gettext('This codename is what you will use in future visits to receive messages from our team in response to what you submit on the next screen.') }}

+

+ {{ gettext('This codename is what you will use in future visits to receive messages from our team in response to what you submit on the next screen.') }} +

{{ gettext('Codename') }}

- {{ codename }} + {{ codename }}
@@ -20,7 +24,8 @@

{{ gettext('Codename') }}

-

{{ gettext('Because we do not track users of our SecureDrop +

+ {{ gettext('Because we do not track users of our SecureDrop service, in future visits, using this codename will be the only way we have to communicate with you should we have questions or are interested in additional information. Unlike passwords, there is no way to retrieve a lost codename.') }}

@@ -28,8 +33,9 @@

{{ gettext('Codename') }}

- -{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/securedrop/source_templates/index.html b/securedrop/source_templates/index.html index d0999e1524..363405cea1 100644 --- a/securedrop/source_templates/index.html +++ b/securedrop/source_templates/index.html @@ -1,90 +1,111 @@ - - {% if g.organization_name == "SecureDrop" %} - {{ g.organization_name }} | {{ gettext('Protecting Journalists and Sources') }} - {% else %} - {{ g.organization_name }} | {{ gettext('SecureDrop') }} - {% endif %} - - - - + + {% if g.organization_name == "SecureDrop" %} + {{ g.organization_name }} | {{ gettext('Protecting Journalists and Sources') }} + {% else %} + {{ g.organization_name }} | {{ gettext('SecureDrop') }} + {% endif %} - {% assets filters="jsmin", output="gen/source.js", "js/source.js" %} - - {% endassets %} - - - - {# Warning bubble to help TB users disable JavaScript with NoScript. + + + + + + {% assets filters="jsmin", output="gen/source.js", "js/source.js" %} + + {% endassets %} + + + + + {# Warning bubble to help TB users disable JavaScript with NoScript. Included here so the images can preload while the user is first reading the page. Hidden by default. #} - - -
    -
  1. {{ gettext('Click the "Security Level" button in the toolbar above').format(icon=url_for("static", filename="i/font-awesome/black/guard.svg")) }}
  2. -
  3. {{ gettext('Select Advanced Security Settings') }}
  4. -
  5. {{ gettext('Select Safest') }}
  6. -
-

{{ gettext('Refresh this page, and you\'re done!') }}

+ + +
    +
  1. + {{ gettext('Click the "Security Level" button in the toolbar above').format(icon=url_for("static", filename="i/font-awesome/black/guard.svg")) }} +
  2. +
  3. {{ gettext('Select Advanced Security Settings') }}
  4. +
  5. {{ gettext('Select Safest') }}
  6. +
+

+ {{ gettext('Refresh this page, and you\'re done!') }} +

-
- - +
+ + - {% include 'banner_warning_flashed.html' %} + {% include 'banner_warning_flashed.html' %} -
-
- {% include 'flashed.html' %} - {# The div `index-wrap` MUST be ordered this way so that the flexbox works on large and small screens +
+
+ {% include 'flashed.html' %} + {# The div `index-wrap` MUST be ordered this way so that the flexbox works on large and small screens See _source_index.sass for a more full understanding. #} -
-
-

{{ gettext('{} logo'.format(g.organization_name)) }}

-
- {% include 'locales.html' %} -
-
+
+
+

{{ gettext('{} logo'.format(g.organization_name)) }} +

+
+ {% include 'locales.html' %} +
+
-
-
-
+
+
+

{{ gettext('First submission') }}

{{ gettext('First time submitting to our SecureDrop? Start here.') }}

-
- -
-
-
-
+
+ +
+
+
+

{{ gettext('Return visit') }}

-

{{ gettext('Already have a codename? Check for replies or submit something new.') }}

-
- -
-
-
- {% include 'footer.html' %} +

+ {{ gettext('Already have a codename? Check for replies or submit something new.') }}

+
+ + +
+ {% include 'footer.html' %}
+
+ + - - + \ No newline at end of file diff --git a/securedrop/source_templates/locales.html b/securedrop/source_templates/locales.html index 49763ec447..760bfa12aa 100644 --- a/securedrop/source_templates/locales.html +++ b/securedrop/source_templates/locales.html @@ -6,27 +6,29 @@

{{ gettext('Enter Codename') }}

- + -
- {% set aria_attributes = {'aria-label': gettext('Enter your codename'), 'aria-required': 'true'} %} - {% if form.codename.errors %} - {% set _dummy = aria_attributes.update({'aria-describedby': 'flashed login-with-existing-code-name-errors', 'aria-invalid': 'true'}) %} - {% endif %} - {{ form.codename(id='login-with-existing-codename', class='codename-box', autocomplete='off', placeholder=gettext('Enter your codename'), autofocus=True, **aria_attributes) }} - {% if form.codename.errors %} +
+ {% set aria_attributes = {'aria-label': gettext('Enter your codename'), 'aria-required': 'true'} %} + {% if form.codename.errors %} + {% set _dummy = aria_attributes.update({'aria-describedby': 'flashed login-with-existing-code-name-errors', 'aria-invalid': 'true'}) %} + {% endif %} + {{ form.codename(id='login-with-existing-codename', class='codename-box', autocomplete='off', placeholder=gettext('Enter your codename'), autofocus=True, **aria_attributes) }} + {% if form.codename.errors %} - {% endif %} + {% endif %}
-
- - - {{ gettext('CANCEL') }} -
+
+ + + {{ gettext('CANCEL') }} +
-{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/securedrop/source_templates/logout.html b/securedrop/source_templates/logout.html index 5fcab4f7e0..ae2974b9e6 100644 --- a/securedrop/source_templates/logout.html +++ b/securedrop/source_templates/logout.html @@ -1,10 +1,13 @@ {% extends "base.html" %} {% block body %} - -
+ +

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

-

{{ gettext('Click the  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 %} +

+ {{ gettext('Click the  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 %} \ No newline at end of file diff --git a/securedrop/source_templates/lookup.html b/securedrop/source_templates/lookup.html index 614db14a56..095bcb3a65 100644 --- a/securedrop/source_templates/lookup.html +++ b/securedrop/source_templates/lookup.html @@ -3,8 +3,8 @@ {% block body %} {% if new_user %}
- {{ gettext('Remember, your codename is:') }} - {{ codename }} + {{ gettext('Remember, your codename is:') }} + {{ codename }}
{% endif %} @@ -13,79 +13,88 @@
-{% if allow_document_uploads %} -

{{ gettext('Submit Files or Messages') }}

-

{{ gettext('You can submit any kind of file, a message, or both.') }}

-{% else %} -

{{ gettext('Submit Messages') }}

-{% endif %} + {% if allow_document_uploads %} +

{{ gettext('Submit Files or Messages') }}

+

{{ gettext('You can submit any kind of file, a message, or both.') }}

+ {% else %} +

{{ gettext('Submit Messages') }}

+ {% endif %} -

-{% if allow_document_uploads %} -{{ gettext('If you are already familiar with GPG, you can optionally encrypt your files and messages with our public key before submission. Files are encrypted as they are received by SecureDrop.').format(url=url_for('info.download_public_key')) }} -{% else %} -{{ gettext('If you are already familiar with GPG, you can optionally encrypt your messages with our public key before submission.').format(url=url_for('info.download_public_key')) }} -{% endif %} -{{ gettext('Learn more.').format(url=url_for('info.why_download_public_key')) }}

+

+ {% if allow_document_uploads %} + {{ gettext('If you are already familiar with GPG, you can optionally encrypt your files and messages with our public key before submission. Files are encrypted as they are received by SecureDrop.').format(url=url_for('info.download_public_key')) }} + {% else %} + {{ gettext('If you are already familiar with GPG, you can optionally encrypt your messages with our public key before submission.').format(url=url_for('info.download_public_key')) }} + {% endif %} + {{ gettext('Learn more.').format(url=url_for('info.why_download_public_key')) }} +

-
- -
-{% if allow_document_uploads %} -
- {{ form.fh(**{"aria-describedby": "max-file-size"}) }} -

{{ gettext('Maximum upload size: 500 MB') }}

-
-{% endif %} -
+ + +
+ {% if allow_document_uploads %} +
+ {{ form.fh(**{"aria-describedby": "max-file-size"}) }} +

{{ gettext('Maximum upload size: 500 MB') }}

+
+ {% endif %} +
{{ form.msg(class="fill-parent") }} +
-
-
- +
+ - - {{ gettext('CANCEL') }} - -
- + + {{ gettext('CANCEL') }} + +
+
-

{{ gettext('Read Replies') }}

+

{{ gettext('Read Replies') }}

-
- {% if replies %} +
+ {% if replies %}

{{ gettext("You have received a reply. To protect your identity in the unlikely event someone learns your codename, please delete all replies when you're done with them. This also lets us know that you are aware of our reply. You can respond by submitting new files and messages above.") }}

{% for reply in replies %} -
-

-
- - - - {{ gettext('Delete') }} - - - -

{{ gettext('Delete this reply?') }} - {{ gettext('Cancel') }} - -

-
-
-
{{ reply.decrypted | nl2br }}
-
+
+

+
+ + + + {{ gettext('Delete') }} + + + +

{{ gettext('Delete this reply?') }} + {{ gettext('Cancel') }} + +

+
+
+
{{ reply.decrypted | nl2br }}
+
{% endfor %}
- {{ gettext('DELETE ALL REPLIES') }} + {{ gettext('DELETE ALL REPLIES') }}

{{ gettext('Are you finished with the replies?') }}

@@ -93,10 +102,10 @@

{{ gettext('Are you finished with the replies?') }}< {{ gettext('NO, NOT YET') }}

- {% else %} + {% else %}

{{ gettext('No Messages') }}

- {% endif %} -
+ {% endif %} +
-{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/securedrop/source_templates/next_submission_flashed_message.html b/securedrop/source_templates/next_submission_flashed_message.html index e2cdf975cb..26c5acc0e9 100644 --- a/securedrop/source_templates/next_submission_flashed_message.html +++ b/securedrop/source_templates/next_submission_flashed_message.html @@ -1,3 +1,3 @@

{{ html_contents }}

-
+ \ No newline at end of file diff --git a/securedrop/source_templates/notfound.html b/securedrop/source_templates/notfound.html index b57d3fb8de..dbb8c46adf 100644 --- a/securedrop/source_templates/notfound.html +++ b/securedrop/source_templates/notfound.html @@ -5,4 +5,4 @@

{{ gettext('Page not found') }}

{{ gettext("Sorry, we couldn't locate what you requested.") }}

{{ gettext('Look up a codename...') }}

-{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/securedrop/source_templates/session_timeout.html b/securedrop/source_templates/session_timeout.html index 4f6b493245..ee1ef96f2e 100644 --- a/securedrop/source_templates/session_timeout.html +++ b/securedrop/source_templates/session_timeout.html @@ -2,5 +2,7 @@

{{ gettext('Important') }}

-

{{ gettext('You were logged out due to inactivity. Click the  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')) }}

-
+

+ {{ gettext('You were logged out due to inactivity. Click the  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')) }} +

+
\ No newline at end of file diff --git a/securedrop/source_templates/tor2web-warning.html b/securedrop/source_templates/tor2web-warning.html index 82aa60d66f..62f40be8cd 100644 --- a/securedrop/source_templates/tor2web-warning.html +++ b/securedrop/source_templates/tor2web-warning.html @@ -2,6 +2,8 @@ {% block body %}

{{ gettext('Why is there a warning about Tor2Web?') }}

{{ gettext('Using Tor2Web to connect to SecureDrop will not protect your anonymity.') }}

-

{{ gettext('It could be possible for anyone monitoring your Internet traffic (your government, your Internet provider), to identify you.') }}

-

{{ gettext('We strongly advise you to use the Tor Browser instead.') }}

-{% endblock %} +

{{ gettext('It could be possible for anyone monitoring your Internet traffic (your government, your Internet provider), to identify you.') }} +

+

{{ gettext('We strongly advise you to use the Tor Browser instead.') }} +

+{% endblock %} \ No newline at end of file diff --git a/securedrop/source_templates/use-tor-browser.html b/securedrop/source_templates/use-tor-browser.html index 551133162c..86318f0bae 100644 --- a/securedrop/source_templates/use-tor-browser.html +++ b/securedrop/source_templates/use-tor-browser.html @@ -2,8 +2,11 @@ {% block body %}

{{ gettext('You Should Use Tor Browser') }}

{{ gettext('If you are not using Tor Browser, you may not be anonymous.') }}

-

{{ gettext('If you want to submit information to SecureDrop, we strongly advise you to install Tor Browser and use it to access our site safely and anonymously.') }}

-

{{ gettext('Copy and paste the following address into your browser and follow the instructions to download and install Tor Browser:') }}

+

{{ gettext('If you want to submit information to SecureDrop, we strongly advise you to install Tor Browser and use it to access our site safely and anonymously.') }} +

+

{{ gettext('Copy and paste the following address into your browser and follow the instructions to download and install Tor Browser:') }} +

https://www.torproject.org/projects/torbrowser.html
-

{{ gettext('If there is a chance that downloading Tor Browser raises suspicion and your mail provider is less likely to be monitored, you can send a mail to gettor@torproject.org and a bot will answer with instructions.') }}

-{% endblock %} +

{{ gettext('If there is a chance that downloading Tor Browser raises suspicion and your mail provider is less likely to be monitored, you can send a mail to gettor@torproject.org and a bot will answer with instructions.') }} +

+{% endblock %} \ No newline at end of file diff --git a/securedrop/source_templates/why-public-key.html b/securedrop/source_templates/why-public-key.html index 8b3df3dee0..ce19128c72 100644 --- a/securedrop/source_templates/why-public-key.html +++ b/securedrop/source_templates/why-public-key.html @@ -1,26 +1,33 @@ {% extends "base.html" %} {% block body %}

{{ gettext("Why download the team's public key?") }}

-

{{ gettext("SecureDrop encrypts files and messages after they are submitted. Encrypting messages and files before submission can provide an extra layer of security before your data reaches the SecureDrop server.") }}

+

{{ gettext("SecureDrop encrypts files and messages after they are submitted. Encrypting messages and files before submission can provide an extra layer of security before your data reaches the SecureDrop server.") }} +

{{ gettext("If you are already familiar with the GPG encryption software, you may wish to encrypt your submissions yourself. To do so:") }}

  1. {{ gettext('Download the public key. It will be saved to a file called: -

    {submission_key_fpr_filename}

    ').format(url=url_for('info.download_public_key'), submission_key_fpr_filename=submission_key_fpr + '.asc')|safe }}
  2. -
  3. {{ gettext('Import it into your GPG keyring.') }} -
      -
    • {{ gettext('If you are using Tails, you can double-click the .asc file you just downloaded and it will be automatically imported to your keyring.').format(url='https://tails.boum.org') }}
    • -
    • {{ gettext('If you are using macOS or Linux, open the terminal. You can import the key with:

      gpg --import /path/to/{submission_key_fpr_filename}

      ').format(url_for('info.download_public_key'), submission_key_fpr_filename=submission_key_fpr + '.asc')|safe }}
    • -
    -
  4. -
  5. {{ gettext('Encrypt your submission. Open the terminal and enter this gpg command:') }} -

    {{ gettext('gpg --recipient \'{submission_key_fpr}\' --encrypt /path/to/submission').format(submission_key_fpr=submission_key_fpr)|safe }}

    -
  6. -
  7. {{ gettext('Upload your encrypted submission. It will have the same filename as the unencrypted file, with .gpg at the end (e.g. internal_memo.pdf.gpg)') }}
  8. +

    {submission_key_fpr_filename}

    ').format(url=url_for('info.download_public_key'), submission_key_fpr_filename=submission_key_fpr + '.asc')|safe }} + +
  9. {{ gettext('Import it into your GPG keyring.') }} +
      +
    • {{ gettext('If you are using Tails, you can double-click the .asc file you just downloaded and it will be automatically imported to your keyring.').format(url='https://tails.boum.org') }} +
    • +
    • {{ gettext('If you are using macOS or Linux, open the terminal. You can import the key with:

      gpg --import /path/to/{submission_key_fpr_filename}

      ').format(url_for('info.download_public_key'), submission_key_fpr_filename=submission_key_fpr + '.asc')|safe }} +
    • +
    +
  10. +
  11. {{ gettext('Encrypt your submission. Open the terminal and enter this gpg command:') }} +

    {{ gettext('gpg --recipient \'{submission_key_fpr}\' --encrypt /path/to/submission').format(submission_key_fpr=submission_key_fpr)|safe }} +

    +
  12. +
  13. {{ gettext('Upload your encrypted submission. It will have the same filename as the unencrypted file, with .gpg at the end (e.g. internal_memo.pdf.gpg)') }} +
-

{{ gettext('Important: If you wish to remain anonymous, do not use GPG to sign the encrypted file (with the --sign or -s flag) as this will reveal your GPG identity to us.')|safe }}

+

{{ gettext('Important: If you wish to remain anonymous, do not use GPG to sign the encrypted file (with the --sign or -s flag) as this will reveal your GPG identity to us.')|safe }} +

{{ gettext('Back to submission page') }}

-{% endblock %} +{% endblock %} \ No newline at end of file