diff --git a/functional_tests/features/tor.feature b/functional_tests/features/tor.feature
index a9589a635..84574fee7 100644
--- a/functional_tests/features/tor.feature
+++ b/functional_tests/features/tor.feature
@@ -15,7 +15,7 @@
# along with this program. If not, see .
#
-@apps @tor
+@apps @tor-app @backups
Feature: Tor Anonymity Network
Manage Tor configuration.
@@ -28,6 +28,30 @@ Scenario: Enable tor application
When I enable the tor application
Then the tor service should be running
+Scenario: Set tor relay configuration
+ Given tor relay is disabled
+ When I enable tor relay
+ Then tor relay should be enabled
+ And tor orport port should be displayed
+
+Scenario: Set tor bridge relay configuration
+ Given tor bridge relay is disabled
+ When I enable tor bridge relay
+ Then tor bridge relay should be enabled
+ And tor obfs3 port should be displayed
+ And tor obfs4 port should be displayed
+
+Scenario: Set tor hidden services configuration
+ Given tor hidden services are disabled
+ When I enable tor hidden services
+ Then tor hidden services should be enabled
+ And tor hidden services information should be displayed
+
+Scenario: Set download software packages over tor
+ Given download software packages over tor is disabled
+ When I enable download software packages over tor
+ Then download software packages over tor should be enabled
+
Scenario: Disable tor application
Given the tor application is enabled
When I disable the tor application
diff --git a/functional_tests/step_definitions/application.py b/functional_tests/step_definitions/application.py
index 794148222..7085e1f92 100644
--- a/functional_tests/step_definitions/application.py
+++ b/functional_tests/step_definitions/application.py
@@ -257,3 +257,74 @@ def ejabberd_delete_contact(browser):
@then('I should have a contact on my roster')
def ejabberd_should_have_contact(browser):
assert application.ejabberd_has_contact(browser)
+
+
+@given(parsers.parse('tor relay is {enabled:w}'))
+def tor_given_relay_enable(browser, enabled):
+ application.tor_feature_enable(browser, 'relay', enabled)
+
+
+@when(parsers.parse('I {enable:w} tor relay'))
+def tor_relay_enable(browser, enable):
+ application.tor_feature_enable(browser, 'relay', enable)
+
+
+@then(parsers.parse('tor relay should be {enabled:w}'))
+def tor_assert_relay_enabled(browser, enabled):
+ application.tor_assert_feature_enabled(browser, 'relay', enabled)
+
+
+@then(parsers.parse('tor {port_name:w} port should be displayed'))
+def tor_assert_port_displayed(browser, port_name):
+ assert port_name in application.tor_get_relay_ports(browser)
+
+
+@given(parsers.parse('tor bridge relay is {enabled:w}'))
+def tor_given_bridge_relay_enable(browser, enabled):
+ application.tor_feature_enable(browser, 'bridge-relay', enabled)
+
+
+@when(parsers.parse('I {enable:w} tor bridge relay'))
+def tor_bridge_relay_enable(browser, enable):
+ application.tor_feature_enable(browser, 'bridge-relay', enable)
+
+
+@then(parsers.parse('tor bridge relay should be {enabled:w}'))
+def tor_assert_bridge_relay_enabled(browser, enabled):
+ application.tor_assert_feature_enabled(browser, 'bridge-relay', enabled)
+
+
+@given(parsers.parse('tor hidden services are {enabled:w}'))
+def tor_given_hidden_services_enable(browser, enabled):
+ application.tor_feature_enable(browser, 'hidden-services', enabled)
+
+
+@when(parsers.parse('I {enable:w} tor hidden services'))
+def tor_hidden_services_enable(browser, enable):
+ application.tor_feature_enable(browser, 'hidden-services', enable)
+
+
+@then(parsers.parse('tor hidden services should be {enabled:w}'))
+def tor_assert_hidden_services_enabled(browser, enabled):
+ application.tor_assert_feature_enabled(browser, 'hidden-services', enabled)
+
+
+@then(parsers.parse('tor hidden services information should be displayed'))
+def tor_assert_hidden_services(browser):
+ application.tor_assert_hidden_services(browser)
+
+
+@given(parsers.parse('download software packages over tor is {enabled:w}'))
+def tor_given_download_software_over_tor_enable(browser, enabled):
+ application.tor_feature_enable(browser, 'software', enabled)
+
+
+@when(parsers.parse('I {enable:w} download software packages over tor'))
+def tor_download_software_over_tor_enable(browser, enable):
+ application.tor_feature_enable(browser, 'software', enable)
+
+
+@then(
+ parsers.parse('download software packages over tor should be {enabled:w}'))
+def tor_assert_download_software_over_tor(browser, enabled):
+ application.tor_assert_feature_enabled(browser, 'software', enabled)
diff --git a/functional_tests/support/application.py b/functional_tests/support/application.py
index 49a6a0dd8..390809ad3 100644
--- a/functional_tests/support/application.py
+++ b/functional_tests/support/application.py
@@ -335,3 +335,59 @@ def time_zone_get(browser):
"""Set the system time zone."""
interface.nav_to_module(browser, 'datetime')
return browser.find_by_name('time_zone').first.value
+
+
+_TOR_FEATURE_TO_ELEMENT = {
+ 'relay': 'tor-relay_enabled',
+ 'bridge-relay': 'tor-bridge_relay_enabled',
+ 'hidden-services': 'tor-hs_enabled',
+ 'software': 'tor-apt_transport_tor_enabled'
+}
+
+
+def tor_feature_enable(browser, feature, should_enable):
+ """Enable/disable a Tor feature."""
+ if not isinstance(should_enable, bool):
+ should_enable = should_enable in ('enable', 'enabled')
+
+ element_name = _TOR_FEATURE_TO_ELEMENT[feature]
+ interface.nav_to_module(browser, 'tor')
+ checkbox_element = browser.find_by_name(element_name).first
+ if should_enable == checkbox_element.checked:
+ return
+
+ if should_enable:
+ if feature == 'bridge-relay':
+ browser.find_by_name('tor-relay_enabled').first.check()
+
+ checkbox_element.check()
+ else:
+ checkbox_element.uncheck()
+
+ interface.submit(browser, form_class='form-configuration')
+ wait_for_config_update(browser, 'tor')
+
+
+def tor_assert_feature_enabled(browser, feature, enabled):
+ """Assert whether Tor relay is enabled or disabled."""
+ if not isinstance(enabled, bool):
+ enabled = enabled in ('enable', 'enabled')
+
+ element_name = _TOR_FEATURE_TO_ELEMENT[feature]
+ interface.nav_to_module(browser, 'tor')
+ assert browser.find_by_name(element_name).first.checked == enabled
+
+
+def tor_get_relay_ports(browser):
+ """Return the list of ports shown in the relay table."""
+ interface.nav_to_module(browser, 'tor')
+ return [
+ port_name.text
+ for port_name in browser.find_by_css('.tor-relay-port-name')
+ ]
+
+
+def tor_assert_hidden_services(browser):
+ """Assert that hidden service information is shown."""
+ interface.nav_to_module(browser, 'tor')
+ assert browser.find_by_css('.tor-hs .tor-hs-hostname')
diff --git a/plinth/modules/tor/templates/tor.html b/plinth/modules/tor/templates/tor.html
index c16934bd4..2a168a64d 100644
--- a/plinth/modules/tor/templates/tor.html
+++ b/plinth/modules/tor/templates/tor.html
@@ -61,7 +61,7 @@
{% include "diagnostics_button.html" with module="tor" enabled=status.enabled %}
{% if status.hs_enabled %}
-
+
| {% trans "Hidden Service" %} |
@@ -71,9 +71,9 @@
- | {{ status.hs_hostname }} |
- {{ status.hs_status }} |
-
+ | {{ status.hs_hostname }} |
+ {{ status.hs_status }} |
+
{% for service in status.hs_services %}
{{ service }}
{% endfor %}
@@ -107,7 +107,7 @@
-
+
| {% trans "Service" %} |
@@ -117,8 +117,8 @@
{% for name, port in status.ports.items %}
- | {{ name }} |
- {{ port }} |
+ {{ name }} |
+ {{ port }} |
{% endfor %}
|