Repository: freedomofpress/securedrop

Issue:
Remove support for v2 Onion Services
## Description

Tor Onion Services V2 support will be disabled in clients on October 15th 2021 [1]
In https://github.com/freedomofpress/securedrop/issues/2951, we introduced support for v3 onion services, and #4768 , we on restricting the use of Onion Services to v3-only

This ticket is to track the removal of all onion service v2 functionality alongside the transition to Ubuntu 20.04.

[1] https://blog.torproject.org/v2-deprecation-timeline



Discussion:
we should probably remove outdated tor2web logic as part of this effort as it no longer seems to be maintained. @redshiftzero pays closer attention to the ongoings in torland, mind providing feedback here?
Since there isn't v3 support in tor2web and it hasn't had commits in a couple years (I also couldn't find any working relays), I think it's fine to remove... if Tor2Web sees a big resurgence of use you could add it back if/when that happens

Resolving patch:
diff --git a/securedrop/source_app/api.py b/securedrop/source_app/api.py
--- a/securedrop/source_app/api.py
+++ b/securedrop/source_app/api.py
@@ -4,7 +4,7 @@
 from flask import Blueprint, current_app, make_response
 
 from sdconfig import SDConfig
-from source_app.utils import get_sourcev2_url, get_sourcev3_url
+from source_app.utils import get_sourcev3_url
 
 import server_os
 import version
@@ -22,7 +22,6 @@ def metadata() -> flask.Response:
             'sd_version': version.__version__,
             'server_os': server_os.get_os_release(),
             'supported_languages': config.SUPPORTED_LOCALES,
-            'v2_source_url': get_sourcev2_url(),
             'v3_source_url': get_sourcev3_url()
         }
         resp = make_response(json.dumps(meta))
diff --git a/securedrop/source_app/utils.py b/securedrop/source_app/utils.py
--- a/securedrop/source_app/utils.py
+++ b/securedrop/source_app/utils.py
@@ -118,7 +118,7 @@ def check_url_file(path: str, regexp: str) -> 'Optional[str]':
     """
     Check that a file exists at the path given and contains a single line
     matching the regexp. Used for checking the source interface address
-    files at /var/lib/securedrop/source_{v2,v3}_url.
+    files in /var/lib/securedrop (as the Apache user can't read Tor config)
     """
     try:
         f = open(path, "r")
@@ -132,11 +132,6 @@ def check_url_file(path: str, regexp: str) -> 'Optional[str]':
         return None
 
 
-def get_sourcev2_url() -> 'Optional[str]':
-    return check_url_file("/var/lib/securedrop/source_v2_url",
-                          r"^[a-z0-9]{16}\.onion$")
-
-
 def get_sourcev3_url() -> 'Optional[str]':
     return check_url_file("/var/lib/securedrop/source_v3_url",
                           r"^[a-z0-9]{56}\.onion$")


Test patch:
diff --git a/securedrop/tests/functional/source_navigation_steps.py b/securedrop/tests/functional/source_navigation_steps.py
--- a/securedrop/tests/functional/source_navigation_steps.py
+++ b/securedrop/tests/functional/source_navigation_steps.py
@@ -32,7 +32,7 @@ def _source_visits_source_homepage(self):
     def _source_checks_instance_metadata(self):
         self.driver.get(self.source_location + "/metadata")
         j = json.loads(self.driver.find_element_by_tag_name("body").text)
-        assert j["server_os"] in ["16.04", "20.04"]
+        assert j["server_os"] == "20.04"
         assert j["sd_version"] == self.source_app.jinja_env.globals["version"]
         assert j["gpg_fpr"] != ""
 
diff --git a/securedrop/tests/test_source.py b/securedrop/tests/test_source.py
--- a/securedrop/tests/test_source.py
+++ b/securedrop/tests/test_source.py
@@ -619,7 +619,7 @@ def test_why_journalist_key(source_app):
 
 
 def test_metadata_route(config, source_app):
-    with patch("server_os.get_os_release", return_value="16.04"):
+    with patch("server_os.get_os_release", return_value="20.04"):
         with source_app.test_client() as app:
             resp = app.get(url_for('api.metadata'))
             assert resp.status_code == 200
@@ -627,22 +627,9 @@ def test_metadata_route(config, source_app):
             assert resp.json.get('allow_document_uploads') ==\
                 InstanceConfig.get_current().allow_document_uploads
             assert resp.json.get('sd_version') == version.__version__
-            assert resp.json.get('server_os') == '16.04'
+            assert resp.json.get('server_os') == '20.04'
             assert resp.json.get('supported_languages') ==\
                 config.SUPPORTED_LOCALES
-            assert resp.json.get('v2_source_url') is None
-            assert resp.json.get('v3_source_url') is None
-
-
-def test_metadata_v2_url(config, source_app):
-    onion_test_url = "abcdabcdabcdabcd.onion"
-    with patch.object(source_app_api, "get_sourcev2_url") as mocked_v2_url:
-        mocked_v2_url.return_value = (onion_test_url)
-        with source_app.test_client() as app:
-            resp = app.get(url_for('api.metadata'))
-            assert resp.status_code == 200
-            assert resp.headers.get('Content-Type') == 'application/json'
-            assert resp.json.get('v2_source_url') == onion_test_url
             assert resp.json.get('v3_source_url') is None
 
 
@@ -654,7 +641,6 @@ def test_metadata_v3_url(config, source_app):
             resp = app.get(url_for('api.metadata'))
             assert resp.status_code == 200
             assert resp.headers.get('Content-Type') == 'application/json'
-            assert resp.json.get('v2_source_url') is None
             assert resp.json.get('v3_source_url') == onion_test_url