Repository: freedomofpress/securedrop

Issue:
The Source Interface's /journalist-key endpoint returns a 404 instead of the Submission Key
## Description

The submission key should be available via the Source Interface at the URL http://[Onion address]/journalist-key, but said URL returns a 404 instead.

## Steps to Reproduce

- set up a production SecureDrop instance on HW or VMs
- visit the source interface, click through to the submission page, and click the ``public key`` link.

## Expected Behavior
The Source Interface responds with the Submission Key

## Actual Behavior
The Source Interface responds with a 404, and the following errors are recorded if logging is enabled:
```
[Thu Jun 13 17:22:12.285962 2019] [authz_core:debug] [pid 7030:tid 3881911650048] mod_authz_core.c(835): [client 127.0.0.1:45900] AH01628: authorization result: granted (no directives), referer: http://fehpa6pmg6ke4i3u.onion/lookup
[Thu Jun 13 17:22:12.286129 2019] [authz_core:debug] [pid 7030:tid 3881911650048] mod_authz_core.c(835): [client 127.0.0.1:45900] AH01628: authorization result: granted (no directives), referer: http://fehpa6pmg6ke4i3u.onion/lookup
[Thu Jun 13 17:22:12.415949 2019] [wsgi:error] [pid 7028:tid 3882000488192] [remote 127.0.0.1:20954] mod_wsgi (pid=7028): Exception occurred processing WSGI script '/var/www/source.wsgi'.
[Thu Jun 13 17:22:12.416036 2019] [wsgi:error] [pid 7028:tid 3882000488192] [remote 127.0.0.1:20954] TypeError: file like object yielded non string type
[Thu Jun 13 17:22:12.416281 2019] [authz_core:debug] [pid 7030:tid 3881911650048] mod_authz_core.c(835): [client 127.0.0.1:45900] AH01628: authorization result: granted (no directives), referer: http://fehpa6pmg6ke4i3u.onion/lookup
[Thu Jun 13 17:22:12.416360 2019] [authz_core:debug] [pid 7030:tid 3881911650048] mod_authz_core.c(835): [client 127.0.0.1:45900] AH01628: authorization result: granted (no directives), referer: http://fehpa6pmg6ke4i3u.onion/lookup
[Thu Jun 13 17:22:13.812032 2019] [authz_core:debug] [pid 7031:tid 3882000144128] mod_authz_core.c(835): [client 127.0.0.1:45902] AH01628: authorization result: granted (no directives), referer: http://fehpa6pmg6ke4i3u.onion/journalist-key
[Thu Jun 13 17:22:14.587228 2019] [authz_core:debug] [pid 7031:tid 3881991599872] mod_authz_core.c(835): [client 127.0.0.1:45902] AH01628: authorization result: granted (no directives), referer: http://fehpa6pmg6ke4i3u.onion/journalist-key
[Thu Jun 13 17:22:14.587409 2019] [authz_core:debug] [pid 7031:tid 3881991599872] mod_authz_core.c(835): [client 127.0.0.1:45902] AH01628: authorization result: granted (no directives), referer: http://fehpa6pmg6ke4i3u.onion/journalist-key
[Thu Jun 13 17:22:15.296269 2019] [authz_core:debug] [pid 7031:tid 3881911961344] mod_authz_core.c(835): [client 127.0.0.1:45902] AH01628: authorization result: granted (no directives), referer: http://fehpa6pmg6ke4i3u.onion/journalist-key
```


Please provide screenshots where appropriate.

## Comments

Suggestions to fix, any other relevant information.



Discussion:

Resolving patch:
diff --git a/securedrop/source_app/info.py b/securedrop/source_app/info.py
--- a/securedrop/source_app/info.py
+++ b/securedrop/source_app/info.py
@@ -1,8 +1,12 @@
 # -*- coding: utf-8 -*-
-
-from io import StringIO
+import six
 from flask import Blueprint, render_template, send_file, current_app
 
+if six.PY2:
+    from cStringIO import StringIO  # noqa
+else:
+    from io import BytesIO  # noqa
+
 
 def make_blueprint(config):
     view = Blueprint('info', __name__)
@@ -19,7 +23,11 @@ def recommend_tor_browser():
     def download_journalist_pubkey():
         journalist_pubkey = current_app.crypto_util.gpg.export_keys(
             config.JOURNALIST_KEY)
-        return send_file(StringIO(journalist_pubkey),
+        if six.PY2:
+            data = StringIO(journalist_pubkey)
+        else:
+            data = BytesIO(journalist_pubkey.encode('utf-8'))
+        return send_file(data,
                          mimetype="application/pgp-keys",
                          attachment_filename=config.JOURNALIST_KEY + ".asc",
                          as_attachment=True)


Test patch:
diff --git a/securedrop/tests/functional/test_source.py b/securedrop/tests/functional/test_source.py
--- a/securedrop/tests/functional/test_source.py
+++ b/securedrop/tests/functional/test_source.py
@@ -1,5 +1,6 @@
-from . import source_navigation_steps
+from . import source_navigation_steps, journalist_navigation_steps
 from . import functional_test
+import six
 
 
 class TestSourceInterface(
@@ -17,3 +18,16 @@ def test_lookup_codename_hint(self):
         self._source_chooses_to_login()
         self._source_proceeds_to_login()
         self._source_sees_no_codename()
+
+
+class TestDownloadKey(
+        functional_test.FunctionalTest,
+        journalist_navigation_steps.JournalistNavigationStepsMixin):
+
+    def test_journalist_key_from_source_interface(self):
+        data = self.return_downloaded_content(self.source_location +
+                                              "/journalist-key", None)
+
+        if six.PY3:
+            data = data.decode('utf-8')
+        assert "BEGIN PGP PUBLIC KEY BLOCK" in data