summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMicah Lee <micah@micahflee.com>2018-12-16 17:01:40 -0800
committerGitHub <noreply@github.com>2018-12-16 17:01:40 -0800
commitc059af97e1f0e484bdfb83521e5bab5e385cdd78 (patch)
treee72c46ad2a5bb24cbc443bfc27974f967229cbaa
parent1f3728e8c55389122f1d692d129980ec03b43780 (diff)
parentbf337b5e34aa3a160938acaf6a2c4f1bcba0db27 (diff)
downloadonionshare-c059af97e1f0e484bdfb83521e5bab5e385cdd78.tar.gz
onionshare-c059af97e1f0e484bdfb83521e5bab5e385cdd78.zip
Merge pull request #831 from micahflee/812_fix_v3_onions
[WIP] Fix v3 onion services
-rw-r--r--onionshare/common.py5
-rw-r--r--onionshare/onion.py10
-rw-r--r--onionshare_gui/settings_dialog.py46
-rw-r--r--share/locale/en.json5
-rw-r--r--tests/SettingsGuiBaseTest.py201
-rw-r--r--tests/local_onionshare_settings_dialog_legacy_tor_test.py24
-rw-r--r--tests/local_onionshare_settings_dialog_no_tor_test.py24
-rw-r--r--tests/local_onionshare_settings_dialog_test.py172
-rw-r--r--tests/local_onionshare_settings_dialog_v3_tor_test.py24
9 files changed, 326 insertions, 185 deletions
diff --git a/onionshare/common.py b/onionshare/common.py
index ffa6529f..250972f9 100644
--- a/onionshare/common.py
+++ b/onionshare/common.py
@@ -373,6 +373,11 @@ class Common(object):
'settings_whats_this': """
QLabel {
font-size: 12px;
+ }""",
+
+ 'settings_connect_to_tor': """
+ QLabel {
+ font-style: italic;
}"""
}
diff --git a/onionshare/onion.py b/onionshare/onion.py
index 6066f059..3d7b4514 100644
--- a/onionshare/onion.py
+++ b/onionshare/onion.py
@@ -146,6 +146,9 @@ class Onion(object):
# The tor process
self.tor_proc = None
+ # The Tor controller
+ self.c = None
+
# Start out not connected to Tor
self.connected_to_tor = False
@@ -387,6 +390,7 @@ class Onion(object):
# Get the tor version
self.tor_version = self.c.get_version().version_str
+ self.common.log('Onion', 'connect', 'Connected to tor {}'.format(self.tor_version))
# Do the versions of stem and tor that I'm using support ephemeral onion services?
list_ephemeral_hidden_services = getattr(self.c, "list_ephemeral_hidden_services", None)
@@ -403,7 +407,9 @@ class Onion(object):
self.supports_stealth = False
# Does this version of Tor support next-gen ('v3') onions?
- self.supports_next_gen_onions = self.tor_version > Version('0.3.3.1')
+ # Note, this is the version of Tor where this bug was fixed:
+ # https://trac.torproject.org/projects/tor/ticket/28619
+ self.supports_v3_onions = self.tor_version >= Version('0.4.0.0')
def is_authenticated(self):
"""
@@ -461,7 +467,7 @@ class Onion(object):
else:
key_type = "NEW"
# Work out if we can support v3 onion services, which are preferred
- if Version(self.tor_version) >= Version('0.3.3.1') and not self.settings.get('use_legacy_v2_onions'):
+ if self.supports_v3_onions and not self.settings.get('use_legacy_v2_onions'):
key_content = "ED25519-V3"
else:
# fall back to v2 onion services
diff --git a/onionshare_gui/settings_dialog.py b/onionshare_gui/settings_dialog.py
index 958d49fd..92c84262 100644
--- a/onionshare_gui/settings_dialog.py
+++ b/onionshare_gui/settings_dialog.py
@@ -88,6 +88,10 @@ class SettingsDialog(QtWidgets.QDialog):
self.shutdown_timeout_widget = QtWidgets.QWidget()
self.shutdown_timeout_widget.setLayout(shutdown_timeout_layout)
+ # Label telling user to connect to Tor for onion service settings
+ self.connect_to_tor_label = QtWidgets.QLabel(strings._("gui_connect_to_tor_for_onion_settings"))
+ self.connect_to_tor_label.setStyleSheet(self.common.css['settings_connect_to_tor'])
+
# Whether or not to use legacy v2 onions
self.use_legacy_v2_onions_checkbox = QtWidgets.QCheckBox()
self.use_legacy_v2_onions_checkbox.setCheckState(QtCore.Qt.Unchecked)
@@ -149,16 +153,23 @@ class SettingsDialog(QtWidgets.QDialog):
self.hidservauth_copy_button.clicked.connect(self.hidservauth_copy_button_clicked)
self.hidservauth_copy_button.hide()
+ # Onion settings widget
+ onion_settings_layout = QtWidgets.QVBoxLayout()
+ onion_settings_layout.setContentsMargins(0, 0, 0, 0)
+ onion_settings_layout.addWidget(self.use_legacy_v2_onions_widget)
+ onion_settings_layout.addWidget(self.save_private_key_widget)
+ onion_settings_layout.addWidget(self.use_stealth_widget)
+ onion_settings_layout.addWidget(hidservauth_details)
+ onion_settings_layout.addWidget(self.hidservauth_copy_button)
+ self.onion_settings_widget = QtWidgets.QWidget()
+ self.onion_settings_widget.setLayout(onion_settings_layout)
+
# General options layout
general_group_layout = QtWidgets.QVBoxLayout()
general_group_layout.addWidget(self.public_mode_widget)
general_group_layout.addWidget(self.shutdown_timeout_widget)
- general_group_layout.addWidget(self.use_legacy_v2_onions_widget)
- general_group_layout.addWidget(self.save_private_key_widget)
- general_group_layout.addWidget(self.use_stealth_widget)
- general_group_layout.addWidget(hidservauth_details)
- general_group_layout.addWidget(self.hidservauth_copy_button)
-
+ general_group_layout.addWidget(self.connect_to_tor_label)
+ general_group_layout.addWidget(self.onion_settings_widget)
general_group = QtWidgets.QGroupBox(strings._("gui_settings_general_label"))
general_group.setLayout(general_group_layout)
@@ -460,6 +471,9 @@ class SettingsDialog(QtWidgets.QDialog):
self.setLayout(layout)
self.cancel_button.setFocus()
+ self.reload_settings()
+
+ def reload_settings(self):
# Load settings, and fill them in
self.old_settings = Settings(self.common, self.config)
self.old_settings.load()
@@ -579,6 +593,24 @@ class SettingsDialog(QtWidgets.QDialog):
new_bridges = ''.join(new_bridges)
self.tor_bridges_use_custom_textbox.setPlainText(new_bridges)
+ # If we're connected to Tor, show onion service settings, show label if not
+ if self.onion.is_authenticated():
+ self.connect_to_tor_label.hide()
+ self.onion_settings_widget.show()
+
+ # If v3 onion services are supported, allow using legacy mode
+ if self.onion.supports_v3_onions:
+ self.common.log('SettingsDialog', '__init__', 'v3 onions are supported')
+ self.use_legacy_v2_onions_checkbox.show()
+ else:
+ self.common.log('SettingsDialog', '__init__', 'v3 onions are not supported')
+ self.use_legacy_v2_onions_widget.hide()
+ self.use_legacy_v2_onions_checkbox_clicked(True)
+ else:
+ self.connect_to_tor_label.show()
+ self.onion_settings_widget.hide()
+
+
def connection_type_bundled_toggled(self, checked):
"""
Connection type bundled was toggled. If checked, hide authentication fields.
@@ -754,7 +786,7 @@ class SettingsDialog(QtWidgets.QDialog):
onion.connect(custom_settings=settings, config=self.config, tor_status_update_func=tor_status_update_func)
# If an exception hasn't been raised yet, the Tor settings work
- Alert(self.common, strings._('settings_test_success').format(onion.tor_version, onion.supports_ephemeral, onion.supports_stealth, onion.supports_next_gen_onions))
+ Alert(self.common, strings._('settings_test_success').format(onion.tor_version, onion.supports_ephemeral, onion.supports_stealth, onion.supports_v3_onions))
# Clean up
onion.cleanup()
diff --git a/share/locale/en.json b/share/locale/en.json
index 7fb30df8..43c7cfe3 100644
--- a/share/locale/en.json
+++ b/share/locale/en.json
@@ -69,7 +69,7 @@
"error_ephemeral_not_supported": "OnionShare requires at least both Tor 0.2.7.1 and python3-stem 1.4.0.",
"gui_settings_window_title": "Settings",
"gui_settings_whats_this": "<a href='{0:s}'>What's this?</a>",
- "gui_settings_stealth_option": "Use client authorization (legacy)",
+ "gui_settings_stealth_option": "Use client authorization",
"gui_settings_stealth_hidservauth_string": "Having saved your private key for reuse, means you can now\nclick to copy your HidServAuth.",
"gui_settings_autoupdate_label": "Check for new version",
"gui_settings_autoupdate_option": "Notify me when a new version is available",
@@ -135,8 +135,9 @@
"gui_server_started_after_timeout": "The auto-stop timer ran out before the server started.\nPlease make a new share.",
"gui_server_timeout_expired": "The auto-stop timer already ran out.\nPlease update it to start sharing.",
"share_via_onionshare": "OnionShare it",
+ "gui_connect_to_tor_for_onion_settings": "Connect to Tor to see onion service settings",
"gui_use_legacy_v2_onions_checkbox": "Use legacy addresses",
- "gui_save_private_key_checkbox": "Use a persistent address (legacy)",
+ "gui_save_private_key_checkbox": "Use a persistent address",
"gui_share_url_description": "<b>Anyone</b> with this OnionShare address can <b>download</b> your files using the <b>Tor Browser</b>: <img src='{}' />",
"gui_receive_url_description": "<b>Anyone</b> with this OnionShare address can <b>upload</b> files to your computer using the <b>Tor Browser</b>: <img src='{}' />",
"gui_url_label_persistent": "This share will not auto-stop.<br><br>Every subsequent share reuses the address. (To use one-time addresses, turn off \"Use persistent address\" in the settings.)",
diff --git a/tests/SettingsGuiBaseTest.py b/tests/SettingsGuiBaseTest.py
index e59a58a8..47d698f3 100644
--- a/tests/SettingsGuiBaseTest.py
+++ b/tests/SettingsGuiBaseTest.py
@@ -1,5 +1,7 @@
import json
import os
+import unittest
+from PyQt5 import QtCore, QtTest
from onionshare import strings
from onionshare.common import Common
@@ -8,10 +10,27 @@ from onionshare.onion import Onion
from onionshare_gui import Application, OnionShare
from onionshare_gui.settings_dialog import SettingsDialog
+
+class OnionStub(object):
+ def __init__(self, is_authenticated, supports_v3_onions):
+ self._is_authenticated = is_authenticated
+ self.supports_v3_onions = supports_v3_onions
+
+ def is_authenticated(self):
+ return self._is_authenticated
+
+
class SettingsGuiBaseTest(object):
@staticmethod
- def set_up(test_settings):
+ def set_up():
'''Create the GUI'''
+
+ # Default settings for the settings GUI tests
+ test_settings = {
+ "no_bridges": False,
+ "tor_bridges_use_custom_bridges": "Bridge 1.2.3.4:56 EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\nBridge 5.6.7.8:910 EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\nBridge 11.12.13.14:1516 EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n",
+ }
+
# Create our test file
testfile = open('/tmp/test.txt', 'w')
testfile.write('onionshare')
@@ -37,8 +56,186 @@ class SettingsGuiBaseTest(object):
gui = SettingsDialog(common, testonion, qtapp, '/tmp/settings.json', True)
return gui
-
@staticmethod
def tear_down():
'''Clean up after tests'''
os.remove('/tmp/settings.json')
+
+ def run_settings_gui_tests(self):
+ self.gui.show()
+
+ # Window is shown
+ self.assertTrue(self.gui.isVisible())
+ self.assertEqual(self.gui.windowTitle(), strings._('gui_settings_window_title'))
+
+ # Check for updates button is hidden
+ self.assertFalse(self.gui.check_for_updates_button.isVisible())
+
+ # public mode is off
+ self.assertFalse(self.gui.public_mode_checkbox.isChecked())
+ # enable public mode
+ QtTest.QTest.mouseClick(self.gui.public_mode_checkbox, QtCore.Qt.LeftButton, pos=QtCore.QPoint(2,self.gui.public_mode_checkbox.height()/2))
+ self.assertTrue(self.gui.public_mode_checkbox.isChecked())
+
+ # shutdown timer is off
+ self.assertFalse(self.gui.shutdown_timeout_checkbox.isChecked())
+ # enable shutdown timer
+ QtTest.QTest.mouseClick(self.gui.shutdown_timeout_checkbox, QtCore.Qt.LeftButton, pos=QtCore.QPoint(2,self.gui.shutdown_timeout_checkbox.height()/2))
+ self.assertTrue(self.gui.shutdown_timeout_checkbox.isChecked())
+
+ # legacy mode checkbox and related widgets
+ if self.gui.onion.is_authenticated():
+ if self.gui.onion.supports_v3_onions:
+ # legacy mode is off
+ self.assertFalse(self.gui.use_legacy_v2_onions_checkbox.isChecked())
+ # persistence, stealth is hidden and disabled
+ self.assertFalse(self.gui.save_private_key_widget.isVisible())
+ self.assertFalse(self.gui.save_private_key_checkbox.isChecked())
+ self.assertFalse(self.gui.use_stealth_widget.isVisible())
+ self.assertFalse(self.gui.stealth_checkbox.isChecked())
+ self.assertFalse(self.gui.hidservauth_copy_button.isVisible())
+
+ # enable legacy mode
+ QtTest.QTest.mouseClick(self.gui.use_legacy_v2_onions_checkbox, QtCore.Qt.LeftButton, pos=QtCore.QPoint(2,self.gui.use_legacy_v2_onions_checkbox.height()/2))
+ self.assertTrue(self.gui.use_legacy_v2_onions_checkbox.isChecked())
+ self.assertTrue(self.gui.save_private_key_checkbox.isVisible())
+ self.assertTrue(self.gui.use_stealth_widget.isVisible())
+
+ # enable persistent mode
+ QtTest.QTest.mouseClick(self.gui.save_private_key_checkbox, QtCore.Qt.LeftButton, pos=QtCore.QPoint(2,self.gui.save_private_key_checkbox.height()/2))
+ self.assertTrue(self.gui.save_private_key_checkbox.isChecked())
+ # enable stealth mode
+ QtTest.QTest.mouseClick(self.gui.stealth_checkbox, QtCore.Qt.LeftButton, pos=QtCore.QPoint(2,self.gui.stealth_checkbox.height()/2))
+ self.assertTrue(self.gui.stealth_checkbox.isChecked())
+ # now that stealth, persistence are enabled, we can't turn off legacy mode
+ self.assertFalse(self.gui.use_legacy_v2_onions_checkbox.isEnabled())
+ # disable stealth, persistence
+ QtTest.QTest.mouseClick(self.gui.save_private_key_checkbox, QtCore.Qt.LeftButton, pos=QtCore.QPoint(2,self.gui.save_private_key_checkbox.height()/2))
+ QtTest.QTest.mouseClick(self.gui.stealth_checkbox, QtCore.Qt.LeftButton, pos=QtCore.QPoint(2,self.gui.stealth_checkbox.height()/2))
+ # legacy mode checkbox is enabled again
+ self.assertTrue(self.gui.use_legacy_v2_onions_checkbox.isEnabled())
+ # uncheck legacy mode
+ QtTest.QTest.mouseClick(self.gui.use_legacy_v2_onions_checkbox, QtCore.Qt.LeftButton, pos=QtCore.QPoint(2,self.gui.use_legacy_v2_onions_checkbox.height()/2))
+ # legacy options hidden again
+ self.assertFalse(self.gui.save_private_key_widget.isVisible())
+ self.assertFalse(self.gui.use_stealth_widget.isVisible())
+
+ # re-enable legacy mode
+ QtTest.QTest.mouseClick(self.gui.use_legacy_v2_onions_checkbox, QtCore.Qt.LeftButton, pos=QtCore.QPoint(2,self.gui.use_legacy_v2_onions_checkbox.height()/2))
+
+ else:
+ # legacy mode setting is hidden
+ self.assertFalse(self.gui.use_legacy_v2_onions_checkbox.isVisible())
+ # legacy options are showing
+ self.assertTrue(self.gui.save_private_key_widget.isVisible())
+ self.assertTrue(self.gui.use_stealth_widget.isVisible())
+
+ # enable them all again so that we can see the setting stick in settings.json
+ QtTest.QTest.mouseClick(self.gui.save_private_key_checkbox, QtCore.Qt.LeftButton, pos=QtCore.QPoint(2,self.gui.save_private_key_checkbox.height()/2))
+ QtTest.QTest.mouseClick(self.gui.stealth_checkbox, QtCore.Qt.LeftButton, pos=QtCore.QPoint(2,self.gui.stealth_checkbox.height()/2))
+ else:
+ # None of the onion settings should appear
+ self.assertFalse(self.gui.use_legacy_v2_onions_checkbox.isVisible())
+ self.assertFalse(self.gui.save_private_key_widget.isVisible())
+ self.assertFalse(self.gui.save_private_key_checkbox.isChecked())
+ self.assertFalse(self.gui.use_stealth_widget.isVisible())
+ self.assertFalse(self.gui.stealth_checkbox.isChecked())
+ self.assertFalse(self.gui.hidservauth_copy_button.isVisible())
+
+ # stay open toggled off, on
+ self.assertTrue(self.gui.close_after_first_download_checkbox.isChecked())
+ QtTest.QTest.mouseClick(self.gui.close_after_first_download_checkbox, QtCore.Qt.LeftButton, pos=QtCore.QPoint(2,self.gui.close_after_first_download_checkbox.height()/2))
+ self.assertFalse(self.gui.close_after_first_download_checkbox.isChecked())
+
+ # receive mode
+ self.gui.downloads_dir_lineedit.setText('/tmp/OnionShareSettingsTest')
+
+
+ # bundled mode is enabled
+ self.assertTrue(self.gui.connection_type_bundled_radio.isEnabled())
+ self.assertTrue(self.gui.connection_type_bundled_radio.isChecked())
+ # bridge options are shown
+ self.assertTrue(self.gui.connection_type_bridges_radio_group.isVisible())
+ # bridges are set to custom
+ self.assertFalse(self.gui.tor_bridges_no_bridges_radio.isChecked())
+ self.assertTrue(self.gui.tor_bridges_use_custom_radio.isChecked())
+
+ # switch to obfs4
+ QtTest.QTest.mouseClick(self.gui.tor_bridges_use_obfs4_radio, QtCore.Qt.LeftButton, pos=QtCore.QPoint(2,self.gui.tor_bridges_use_obfs4_radio.height()/2))
+ self.assertTrue(self.gui.tor_bridges_use_obfs4_radio.isChecked())
+
+ # custom bridges are hidden
+ self.assertFalse(self.gui.tor_bridges_use_custom_textbox_options.isVisible())
+ # other modes are unchecked but enabled
+ self.assertTrue(self.gui.connection_type_automatic_radio.isEnabled())
+ self.assertTrue(self.gui.connection_type_control_port_radio.isEnabled())
+ self.assertTrue(self.gui.connection_type_socket_file_radio.isEnabled())
+ self.assertFalse(self.gui.connection_type_automatic_radio.isChecked())
+ self.assertFalse(self.gui.connection_type_control_port_radio.isChecked())
+ self.assertFalse(self.gui.connection_type_socket_file_radio.isChecked())
+
+ # enable automatic mode
+ QtTest.QTest.mouseClick(self.gui.connection_type_automatic_radio, QtCore.Qt.LeftButton, pos=QtCore.QPoint(2,self.gui.connection_type_automatic_radio.height()/2))
+ self.assertTrue(self.gui.connection_type_automatic_radio.isChecked())
+ # bundled is off
+ self.assertFalse(self.gui.connection_type_bundled_radio.isChecked())
+ # bridges are hidden
+ self.assertFalse(self.gui.connection_type_bridges_radio_group.isVisible())
+
+ # auth type is hidden in bundled or automatic mode
+ self.assertFalse(self.gui.authenticate_no_auth_radio.isVisible())
+ self.assertFalse(self.gui.authenticate_password_radio.isVisible())
+
+ # enable control port mode
+ QtTest.QTest.mouseClick(self.gui.connection_type_control_port_radio, QtCore.Qt.LeftButton, pos=QtCore.QPoint(2,self.gui.connection_type_control_port_radio.height()/2))
+ self.assertTrue(self.gui.connection_type_control_port_radio.isChecked())
+ # automatic is off
+ self.assertFalse(self.gui.connection_type_automatic_radio.isChecked())
+ # auth options appear
+ self.assertTrue(self.gui.authenticate_no_auth_radio.isVisible())
+ self.assertTrue(self.gui.authenticate_password_radio.isVisible())
+
+ # enable socket mode
+ QtTest.QTest.mouseClick(self.gui.connection_type_socket_file_radio, QtCore.Qt.LeftButton, pos=QtCore.QPoint(2,self.gui.connection_type_socket_file_radio.height()/2))
+ self.assertTrue(self.gui.connection_type_socket_file_radio.isChecked())
+ # control port is off
+ self.assertFalse(self.gui.connection_type_control_port_radio.isChecked())
+ # auth options are still present
+ self.assertTrue(self.gui.authenticate_no_auth_radio.isVisible())
+ self.assertTrue(self.gui.authenticate_password_radio.isVisible())
+
+ # re-enable bundled mode
+ QtTest.QTest.mouseClick(self.gui.connection_type_bundled_radio, QtCore.Qt.LeftButton, pos=QtCore.QPoint(2,self.gui.connection_type_bundled_radio.height()/2))
+ # go back to custom bridges
+ QtTest.QTest.mouseClick(self.gui.tor_bridges_use_custom_radio, QtCore.Qt.LeftButton, pos=QtCore.QPoint(2,self.gui.tor_bridges_use_custom_radio.height()/2))
+ self.assertTrue(self.gui.tor_bridges_use_custom_radio.isChecked())
+ self.assertTrue(self.gui.tor_bridges_use_custom_textbox.isVisible())
+ self.assertFalse(self.gui.tor_bridges_use_obfs4_radio.isChecked())
+ self.gui.tor_bridges_use_custom_textbox.setPlainText('94.242.249.2:83 E25A95F1DADB739F0A83EB0223A37C02FD519306\n148.251.90.59:7510 019F727CA6DCA6CA5C90B55E477B7D87981E75BC\n93.80.47.217:41727 A6A0D497D98097FCFE91D639548EE9E34C15CDD3')
+
+ # Test that the Settings Dialog can save the settings and close itself
+ QtTest.QTest.mouseClick(self.gui.save_button, QtCore.Qt.LeftButton)
+ self.assertFalse(self.gui.isVisible())
+
+ # Test our settings are reflected in the settings json
+ with open('/tmp/settings.json') as f:
+ data = json.load(f)
+
+ self.assertTrue(data["public_mode"])
+ self.assertTrue(data["shutdown_timeout"])
+
+ if self.gui.onion.is_authenticated():
+ if self.gui.onion.supports_v3_onions:
+ self.assertTrue(data["use_legacy_v2_onions"])
+ self.assertTrue(data["save_private_key"])
+ self.assertTrue(data["use_stealth"])
+ else:
+ self.assertFalse(data["use_legacy_v2_onions"])
+ self.assertFalse(data["save_private_key"])
+ self.assertFalse(data["use_stealth"])
+
+ self.assertEqual(data["downloads_dir"], "/tmp/OnionShareSettingsTest")
+ self.assertFalse(data["close_after_first_download"])
+ self.assertEqual(data["connection_type"], "bundled")
+ self.assertFalse(data["tor_bridges_use_obfs4"])
+ self.assertEqual(data["tor_bridges_use_custom_bridges"], "Bridge 94.242.249.2:83 E25A95F1DADB739F0A83EB0223A37C02FD519306\nBridge 148.251.90.59:7510 019F727CA6DCA6CA5C90B55E477B7D87981E75BC\nBridge 93.80.47.217:41727 A6A0D497D98097FCFE91D639548EE9E34C15CDD3\n")
diff --git a/tests/local_onionshare_settings_dialog_legacy_tor_test.py b/tests/local_onionshare_settings_dialog_legacy_tor_test.py
new file mode 100644
index 00000000..ae6ce272
--- /dev/null
+++ b/tests/local_onionshare_settings_dialog_legacy_tor_test.py
@@ -0,0 +1,24 @@
+#!/usr/bin/env python3
+import unittest
+
+from onionshare import strings
+from .SettingsGuiBaseTest import SettingsGuiBaseTest, OnionStub
+
+
+class SettingsGuiTest(unittest.TestCase, SettingsGuiBaseTest):
+ @classmethod
+ def setUpClass(cls):
+ cls.gui = SettingsGuiBaseTest.set_up()
+
+ @classmethod
+ def tearDownClass(cls):
+ SettingsGuiBaseTest.tear_down()
+
+ def test_gui_legacy_tor(self):
+ self.gui.onion = OnionStub(True, False)
+ self.gui.reload_settings()
+ self.run_settings_gui_tests()
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tests/local_onionshare_settings_dialog_no_tor_test.py b/tests/local_onionshare_settings_dialog_no_tor_test.py
new file mode 100644
index 00000000..f01e049d
--- /dev/null
+++ b/tests/local_onionshare_settings_dialog_no_tor_test.py
@@ -0,0 +1,24 @@
+#!/usr/bin/env python3
+import unittest
+
+from onionshare import strings
+from .SettingsGuiBaseTest import SettingsGuiBaseTest, OnionStub
+
+
+class SettingsGuiTest(unittest.TestCase, SettingsGuiBaseTest):
+ @classmethod
+ def setUpClass(cls):
+ cls.gui = SettingsGuiBaseTest.set_up()
+
+ @classmethod
+ def tearDownClass(cls):
+ SettingsGuiBaseTest.tear_down()
+
+ def test_gui_no_tor(self):
+ self.gui.onion = OnionStub(False, False)
+ self.gui.reload_settings()
+ self.run_settings_gui_tests()
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tests/local_onionshare_settings_dialog_test.py b/tests/local_onionshare_settings_dialog_test.py
deleted file mode 100644
index c1e48122..00000000
--- a/tests/local_onionshare_settings_dialog_test.py
+++ /dev/null
@@ -1,172 +0,0 @@
-#!/usr/bin/env python3
-import json
-import unittest
-from PyQt5 import QtCore, QtTest
-
-from onionshare import strings
-from .SettingsGuiBaseTest import SettingsGuiBaseTest
-
-class SettingsGuiTest(unittest.TestCase, SettingsGuiBaseTest):
- @classmethod
- def setUpClass(cls):
- test_settings = {
- "no_bridges": False,
- "tor_bridges_use_custom_bridges": "Bridge 1.2.3.4:56 EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\nBridge 5.6.7.8:910 EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\nBridge 11.12.13.14:1516 EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n",
- }
- cls.gui = SettingsGuiBaseTest.set_up(test_settings)
-
- @classmethod
- def tearDownClass(cls):
- SettingsGuiBaseTest.tear_down()
-
- def test_gui(self):
- self.gui.show()
- # Window is shown
- self.assertTrue(self.gui.isVisible())
- self.assertEqual(self.gui.windowTitle(), strings._('gui_settings_window_title'))
- # Check for updates button is hidden
- self.assertFalse(self.gui.check_for_updates_button.isVisible())
-
- # public mode is off
- self.assertFalse(self.gui.public_mode_checkbox.isChecked())
- # enable public mode
- QtTest.QTest.mouseClick(self.gui.public_mode_checkbox, QtCore.Qt.LeftButton, pos=QtCore.QPoint(2,self.gui.public_mode_checkbox.height()/2))
- self.assertTrue(self.gui.public_mode_checkbox.isChecked())
-
- # shutdown timer is off
- self.assertFalse(self.gui.shutdown_timeout_checkbox.isChecked())
- # enable shutdown timer
- QtTest.QTest.mouseClick(self.gui.shutdown_timeout_checkbox, QtCore.Qt.LeftButton, pos=QtCore.QPoint(2,self.gui.shutdown_timeout_checkbox.height()/2))
- self.assertTrue(self.gui.shutdown_timeout_checkbox.isChecked())
-
- # legacy mode checkbox and related widgets
- # legacy mode is off
- self.assertFalse(self.gui.use_legacy_v2_onions_checkbox.isChecked())
- # persistence, stealth is hidden and disabled
- self.assertFalse(self.gui.save_private_key_widget.isVisible())
- self.assertFalse(self.gui.save_private_key_checkbox.isChecked())
- self.assertFalse(self.gui.use_stealth_widget.isVisible())
- self.assertFalse(self.gui.stealth_checkbox.isChecked())
- self.assertFalse(self.gui.hidservauth_copy_button.isVisible())
-
- # enable legacy mode
- QtTest.QTest.mouseClick(self.gui.use_legacy_v2_onions_checkbox, QtCore.Qt.LeftButton, pos=QtCore.QPoint(2,self.gui.use_legacy_v2_onions_checkbox.height()/2))
- self.assertTrue(self.gui.use_legacy_v2_onions_checkbox.isChecked())
- self.assertTrue(self.gui.save_private_key_checkbox.isVisible())
- self.assertTrue(self.gui.use_stealth_widget.isVisible())
- # enable persistent mode
- QtTest.QTest.mouseClick(self.gui.save_private_key_checkbox, QtCore.Qt.LeftButton, pos=QtCore.QPoint(2,self.gui.save_private_key_checkbox.height()/2))
- self.assertTrue(self.gui.save_private_key_checkbox.isChecked())
- # enable stealth mode
- QtTest.QTest.mouseClick(self.gui.stealth_checkbox, QtCore.Qt.LeftButton, pos=QtCore.QPoint(2,self.gui.stealth_checkbox.height()/2))
- self.assertTrue(self.gui.stealth_checkbox.isChecked())
- # now that stealth, persistence are enabled, we can't turn off legacy mode
- self.assertFalse(self.gui.use_legacy_v2_onions_checkbox.isEnabled())
- # disable stealth, persistence
- QtTest.QTest.mouseClick(self.gui.save_private_key_checkbox, QtCore.Qt.LeftButton, pos=QtCore.QPoint(2,self.gui.save_private_key_checkbox.height()/2))
- QtTest.QTest.mouseClick(self.gui.stealth_checkbox, QtCore.Qt.LeftButton, pos=QtCore.QPoint(2,self.gui.stealth_checkbox.height()/2))
- # legacy mode checkbox is enabled again
- self.assertTrue(self.gui.use_legacy_v2_onions_checkbox.isEnabled())
- # uncheck legacy mode
- QtTest.QTest.mouseClick(self.gui.use_legacy_v2_onions_checkbox, QtCore.Qt.LeftButton, pos=QtCore.QPoint(2,self.gui.use_legacy_v2_onions_checkbox.height()/2))
- # legacy options hidden again
- self.assertFalse(self.gui.save_private_key_widget.isVisible())
- self.assertFalse(self.gui.use_stealth_widget.isVisible())
- # enable them all again so that we can see the setting stick in settings.json
- QtTest.QTest.mouseClick(self.gui.use_legacy_v2_onions_checkbox, QtCore.Qt.LeftButton, pos=QtCore.QPoint(2,self.gui.use_legacy_v2_onions_checkbox.height()/2))
- QtTest.QTest.mouseClick(self.gui.save_private_key_checkbox, QtCore.Qt.LeftButton, pos=QtCore.QPoint(2,self.gui.save_private_key_checkbox.height()/2))
- QtTest.QTest.mouseClick(self.gui.stealth_checkbox, QtCore.Qt.LeftButton, pos=QtCore.QPoint(2,self.gui.stealth_checkbox.height()/2))
-
-
- # stay open toggled off, on
- self.assertTrue(self.gui.close_after_first_download_checkbox.isChecked())
- QtTest.QTest.mouseClick(self.gui.close_after_first_download_checkbox, QtCore.Qt.LeftButton, pos=QtCore.QPoint(2,self.gui.close_after_first_download_checkbox.height()/2))
- self.assertFalse(self.gui.close_after_first_download_checkbox.isChecked())
-
- # receive mode
- self.gui.downloads_dir_lineedit.setText('/tmp/OnionShareSettingsTest')
-
-
- # bundled mode is enabled
- self.assertTrue(self.gui.connection_type_bundled_radio.isEnabled())
- self.assertTrue(self.gui.connection_type_bundled_radio.isChecked())
- # bridge options are shown
- self.assertTrue(self.gui.connection_type_bridges_radio_group.isVisible())
- # bridges are set to custom
- self.assertFalse(self.gui.tor_bridges_no_bridges_radio.isChecked())
- self.assertTrue(self.gui.tor_bridges_use_custom_radio.isChecked())
-
- # switch to obfs4
- QtTest.QTest.mouseClick(self.gui.tor_bridges_use_obfs4_radio, QtCore.Qt.LeftButton, pos=QtCore.QPoint(2,self.gui.tor_bridges_use_obfs4_radio.height()/2))
- self.assertTrue(self.gui.tor_bridges_use_obfs4_radio.isChecked())
-
- # custom bridges are hidden
- self.assertFalse(self.gui.tor_bridges_use_custom_textbox_options.isVisible())
- # other modes are unchecked but enabled
- self.assertTrue(self.gui.connection_type_automatic_radio.isEnabled())
- self.assertTrue(self.gui.connection_type_control_port_radio.isEnabled())
- self.assertTrue(self.gui.connection_type_socket_file_radio.isEnabled())
- self.assertFalse(self.gui.connection_type_automatic_radio.isChecked())
- self.assertFalse(self.gui.connection_type_control_port_radio.isChecked())
- self.assertFalse(self.gui.connection_type_socket_file_radio.isChecked())
-
- # enable automatic mode
- QtTest.QTest.mouseClick(self.gui.connection_type_automatic_radio, QtCore.Qt.LeftButton, pos=QtCore.QPoint(2,self.gui.connection_type_automatic_radio.height()/2))
- self.assertTrue(self.gui.connection_type_automatic_radio.isChecked())
- # bundled is off
- self.assertFalse(self.gui.connection_type_bundled_radio.isChecked())
- # bridges are hidden
- self.assertFalse(self.gui.connection_type_bridges_radio_group.isVisible())
-
- # auth type is hidden in bundled or automatic mode
- self.assertFalse(self.gui.authenticate_no_auth_radio.isVisible())
- self.assertFalse(self.gui.authenticate_password_radio.isVisible())
-
- # enable control port mode
- QtTest.QTest.mouseClick(self.gui.connection_type_control_port_radio, QtCore.Qt.LeftButton, pos=QtCore.QPoint(2,self.gui.connection_type_control_port_radio.height()/2))
- self.assertTrue(self.gui.connection_type_control_port_radio.isChecked())
- # automatic is off
- self.assertFalse(self.gui.connection_type_automatic_radio.isChecked())
- # auth options appear
- self.assertTrue(self.gui.authenticate_no_auth_radio.isVisible())
- self.assertTrue(self.gui.authenticate_password_radio.isVisible())
-
- # enable socket mode
- QtTest.QTest.mouseClick(self.gui.connection_type_socket_file_radio, QtCore.Qt.LeftButton, pos=QtCore.QPoint(2,self.gui.connection_type_socket_file_radio.height()/2))
- self.assertTrue(self.gui.connection_type_socket_file_radio.isChecked())
- # control port is off
- self.assertFalse(self.gui.connection_type_control_port_radio.isChecked())
- # auth options are still present
- self.assertTrue(self.gui.authenticate_no_auth_radio.isVisible())
- self.assertTrue(self.gui.authenticate_password_radio.isVisible())
-
- # re-enable bundled mode
- QtTest.QTest.mouseClick(self.gui.connection_type_bundled_radio, QtCore.Qt.LeftButton, pos=QtCore.QPoint(2,self.gui.connection_type_bundled_radio.height()/2))
- # go back to custom bridges
- QtTest.QTest.mouseClick(self.gui.tor_bridges_use_custom_radio, QtCore.Qt.LeftButton, pos=QtCore.QPoint(2,self.gui.tor_bridges_use_custom_radio.height()/2))
- self.assertTrue(self.gui.tor_bridges_use_custom_radio.isChecked())
- self.assertTrue(self.gui.tor_bridges_use_custom_textbox.isVisible())
- self.assertFalse(self.gui.tor_bridges_use_obfs4_radio.isChecked())
- self.gui.tor_bridges_use_custom_textbox.setPlainText('94.242.249.2:83 E25A95F1DADB739F0A83EB0223A37C02FD519306\n148.251.90.59:7510 019F727CA6DCA6CA5C90B55E477B7D87981E75BC\n93.80.47.217:41727 A6A0D497D98097FCFE91D639548EE9E34C15CDD3')
-
- # Test that the Settings Dialog can save the settings and close itself
- QtTest.QTest.mouseClick(self.gui.save_button, QtCore.Qt.LeftButton)
- self.assertFalse(self.gui.isVisible())
-
- # Test our settings are reflected in the settings json
- with open('/tmp/settings.json') as f:
- data = json.load(f)
-
- self.assertTrue(data["public_mode"])
- self.assertTrue(data["shutdown_timeout"])
- self.assertTrue(data["use_legacy_v2_onions"])
- self.assertTrue(data["save_private_key"])
- self.assertTrue(data["use_stealth"])
- self.assertEqual(data["downloads_dir"], "/tmp/OnionShareSettingsTest")
- self.assertFalse(data["close_after_first_download"])
- self.assertEqual(data["connection_type"], "bundled")
- self.assertFalse(data["tor_bridges_use_obfs4"])
- self.assertEqual(data["tor_bridges_use_custom_bridges"], "Bridge 94.242.249.2:83 E25A95F1DADB739F0A83EB0223A37C02FD519306\nBridge 148.251.90.59:7510 019F727CA6DCA6CA5C90B55E477B7D87981E75BC\nBridge 93.80.47.217:41727 A6A0D497D98097FCFE91D639548EE9E34C15CDD3\n")
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/tests/local_onionshare_settings_dialog_v3_tor_test.py b/tests/local_onionshare_settings_dialog_v3_tor_test.py
new file mode 100644
index 00000000..cb10f8c9
--- /dev/null
+++ b/tests/local_onionshare_settings_dialog_v3_tor_test.py
@@ -0,0 +1,24 @@
+#!/usr/bin/env python3
+import unittest
+
+from onionshare import strings
+from .SettingsGuiBaseTest import SettingsGuiBaseTest, OnionStub
+
+
+class SettingsGuiTest(unittest.TestCase, SettingsGuiBaseTest):
+ @classmethod
+ def setUpClass(cls):
+ cls.gui = SettingsGuiBaseTest.set_up()
+
+ @classmethod
+ def tearDownClass(cls):
+ SettingsGuiBaseTest.tear_down()
+
+ def test_gui_v3_tor(self):
+ self.gui.onion = OnionStub(True, True)
+ self.gui.reload_settings()
+ self.run_settings_gui_tests()
+
+
+if __name__ == "__main__":
+ unittest.main()