mirror of
https://github.com/onionshare/onionshare.git
synced 2025-02-02 09:35:33 -05:00
Merge pull request #1449 from onionshare/1442_settings_tabs
Switch Settings and Tor Settings dialogs into tabs
This commit is contained in:
commit
6a8766671b
@ -310,32 +310,15 @@ class Common:
|
||||
|
||||
def get_tor_paths(self):
|
||||
if self.platform == "Linux":
|
||||
# Look in resources first
|
||||
base_path = self.get_resource_path("tor")
|
||||
if os.path.exists(base_path):
|
||||
self.log(
|
||||
"Common", "get_tor_paths", f"using tor binaries in {base_path}"
|
||||
)
|
||||
tor_path = os.path.join(base_path, "tor")
|
||||
tor_geo_ip_file_path = os.path.join(base_path, "geoip")
|
||||
tor_geo_ipv6_file_path = os.path.join(base_path, "geoip6")
|
||||
obfs4proxy_file_path = os.path.join(base_path, "obfs4proxy")
|
||||
snowflake_file_path = os.path.join(base_path, "snowflake-client")
|
||||
meek_client_file_path = os.path.join(base_path, "meek-client")
|
||||
else:
|
||||
# Fallback to looking in the path
|
||||
self.log(
|
||||
"Common", "get_tor_paths", f"using tor binaries in system path"
|
||||
)
|
||||
tor_path = shutil.which("tor")
|
||||
if not tor_path:
|
||||
raise CannotFindTor()
|
||||
obfs4proxy_file_path = shutil.which("obfs4proxy")
|
||||
snowflake_file_path = shutil.which("snowflake-client")
|
||||
meek_client_file_path = shutil.which("meek-client")
|
||||
prefix = os.path.dirname(os.path.dirname(tor_path))
|
||||
tor_geo_ip_file_path = os.path.join(prefix, "share/tor/geoip")
|
||||
tor_geo_ipv6_file_path = os.path.join(prefix, "share/tor/geoip6")
|
||||
tor_path = shutil.which("tor")
|
||||
if not tor_path:
|
||||
raise CannotFindTor()
|
||||
obfs4proxy_file_path = shutil.which("obfs4proxy")
|
||||
snowflake_file_path = shutil.which("snowflake-client")
|
||||
meek_client_file_path = shutil.which("meek-client")
|
||||
prefix = os.path.dirname(os.path.dirname(tor_path))
|
||||
tor_geo_ip_file_path = os.path.join(prefix, "share/tor/geoip")
|
||||
tor_geo_ipv6_file_path = os.path.join(prefix, "share/tor/geoip6")
|
||||
elif self.platform == "Windows":
|
||||
base_path = self.get_resource_path("tor")
|
||||
tor_path = os.path.join(base_path, "Tor", "tor.exe")
|
||||
@ -345,26 +328,15 @@ class Common:
|
||||
tor_geo_ip_file_path = os.path.join(base_path, "Data", "Tor", "geoip")
|
||||
tor_geo_ipv6_file_path = os.path.join(base_path, "Data", "Tor", "geoip6")
|
||||
elif self.platform == "Darwin":
|
||||
# Look in resources first
|
||||
base_path = self.get_resource_path("tor")
|
||||
if os.path.exists(base_path):
|
||||
tor_path = os.path.join(base_path, "tor")
|
||||
tor_geo_ip_file_path = os.path.join(base_path, "geoip")
|
||||
tor_geo_ipv6_file_path = os.path.join(base_path, "geoip6")
|
||||
obfs4proxy_file_path = os.path.join(base_path, "obfs4proxy")
|
||||
meek_client_file_path = os.path.join(base_path, "meek-client")
|
||||
snowflake_file_path = os.path.join(base_path, "snowflake-client")
|
||||
else:
|
||||
# Fallback to looking in the path
|
||||
tor_path = shutil.which("tor")
|
||||
if not tor_path:
|
||||
raise CannotFindTor()
|
||||
obfs4proxy_file_path = shutil.which("obfs4proxy")
|
||||
snowflake_file_path = shutil.which("snowflake-client")
|
||||
meek_client_file_path = shutil.which("meek-client")
|
||||
prefix = os.path.dirname(os.path.dirname(tor_path))
|
||||
tor_geo_ip_file_path = os.path.join(prefix, "share/tor/geoip")
|
||||
tor_geo_ipv6_file_path = os.path.join(prefix, "share/tor/geoip6")
|
||||
tor_path = shutil.which("tor")
|
||||
if not tor_path:
|
||||
raise CannotFindTor()
|
||||
obfs4proxy_file_path = shutil.which("obfs4proxy")
|
||||
snowflake_file_path = shutil.which("snowflake-client")
|
||||
meek_client_file_path = shutil.which("meek-client")
|
||||
prefix = os.path.dirname(os.path.dirname(tor_path))
|
||||
tor_geo_ip_file_path = os.path.join(prefix, "share/tor/geoip")
|
||||
tor_geo_ipv6_file_path = os.path.join(prefix, "share/tor/geoip6")
|
||||
elif self.platform == "BSD":
|
||||
tor_path = "/usr/local/bin/tor"
|
||||
tor_geo_ip_file_path = "/usr/local/share/tor/geoip"
|
||||
|
@ -85,6 +85,10 @@ class Meek(object):
|
||||
self.common.log("Meek", "start", "Starting meek client")
|
||||
|
||||
if self.common.platform == "Windows":
|
||||
env = os.environ.copy()
|
||||
for key in self.meek_env:
|
||||
env[key] = self.meek_env[key]
|
||||
|
||||
# In Windows, hide console window when opening meek-client.exe subprocess
|
||||
startupinfo = subprocess.STARTUPINFO()
|
||||
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
||||
@ -100,7 +104,7 @@ class Meek(object):
|
||||
stderr=subprocess.PIPE,
|
||||
startupinfo=startupinfo,
|
||||
bufsize=1,
|
||||
env=self.meek_env,
|
||||
env=env,
|
||||
text=True,
|
||||
)
|
||||
else:
|
||||
@ -129,6 +133,7 @@ class Meek(object):
|
||||
# read stdout without blocking
|
||||
try:
|
||||
line = q.get_nowait()
|
||||
self.common.log("Meek", "start", line.strip())
|
||||
except Empty:
|
||||
# no stdout yet?
|
||||
pass
|
||||
@ -136,10 +141,17 @@ class Meek(object):
|
||||
if "CMETHOD meek socks5" in line:
|
||||
self.meek_host = line.split(" ")[3].split(":")[0]
|
||||
self.meek_port = line.split(" ")[3].split(":")[1]
|
||||
self.common.log("Meek", "start", f"Meek host is {self.meek_host}")
|
||||
self.common.log("Meek", "start", f"Meek port is {self.meek_port}")
|
||||
self.common.log(
|
||||
"Meek",
|
||||
"start",
|
||||
f"Meek running on {self.meek_host}:{self.meek_port}",
|
||||
)
|
||||
break
|
||||
|
||||
if "CMETHOD-ERROR" in line:
|
||||
self.cleanup()
|
||||
raise MeekNotRunning()
|
||||
|
||||
if self.meek_port:
|
||||
self.meek_proxies = {
|
||||
"http": f"socks5h://{self.meek_host}:{self.meek_port}",
|
||||
@ -147,6 +159,7 @@ class Meek(object):
|
||||
}
|
||||
else:
|
||||
self.common.log("Meek", "start", "Could not obtain the meek port")
|
||||
self.cleanup()
|
||||
raise MeekNotRunning()
|
||||
|
||||
def cleanup(self):
|
||||
|
@ -200,8 +200,6 @@ class Onion(object):
|
||||
)
|
||||
return
|
||||
|
||||
self.common.log("Onion", "connect")
|
||||
|
||||
# Either use settings that are passed in, or use them from common
|
||||
if custom_settings:
|
||||
self.settings = custom_settings
|
||||
@ -212,6 +210,12 @@ class Onion(object):
|
||||
self.common.load_settings()
|
||||
self.settings = self.common.settings
|
||||
|
||||
self.common.log(
|
||||
"Onion",
|
||||
"connect",
|
||||
f"connection_type={self.settings.get('connection_type')}",
|
||||
)
|
||||
|
||||
# The Tor controller
|
||||
self.c = None
|
||||
|
||||
@ -315,40 +319,39 @@ class Onion(object):
|
||||
f.write(torrc_template)
|
||||
|
||||
# Bridge support
|
||||
if self.settings.get("tor_bridges_use_obfs4"):
|
||||
with open(
|
||||
self.common.get_resource_path("torrc_template-obfs4")
|
||||
) as o:
|
||||
for line in o:
|
||||
f.write(line)
|
||||
elif self.settings.get("tor_bridges_use_meek_lite_azure"):
|
||||
with open(
|
||||
self.common.get_resource_path("torrc_template-meek_lite_azure")
|
||||
) as o:
|
||||
for line in o:
|
||||
f.write(line)
|
||||
elif self.settings.get("tor_bridges_use_snowflake"):
|
||||
with open(
|
||||
self.common.get_resource_path("torrc_template-snowflake")
|
||||
) as o:
|
||||
for line in o:
|
||||
f.write(line)
|
||||
if self.settings.get("bridges_enabled"):
|
||||
if self.settings.get("bridges_type") == "built-in":
|
||||
if self.settings.get("bridges_builtin_pt") == "obfs4":
|
||||
with open(
|
||||
self.common.get_resource_path("torrc_template-obfs4")
|
||||
) as o:
|
||||
f.write(o.read())
|
||||
elif self.settings.get("bridges_builtin_pt") == "meek-azure":
|
||||
with open(
|
||||
self.common.get_resource_path(
|
||||
"torrc_template-meek_lite_azure"
|
||||
)
|
||||
) as o:
|
||||
f.write(o.read())
|
||||
elif self.settings.get("bridges_builtin_pt") == "snowflake":
|
||||
with open(
|
||||
self.common.get_resource_path(
|
||||
"torrc_template-snowflake"
|
||||
)
|
||||
) as o:
|
||||
f.write(o.read())
|
||||
|
||||
elif self.settings.get("tor_bridges_use_moat"):
|
||||
for line in self.settings.get("tor_bridges_use_moat_bridges").split(
|
||||
"\n"
|
||||
):
|
||||
if line.strip() != "":
|
||||
f.write(f"Bridge {line}\n")
|
||||
f.write("\nUseBridges 1\n")
|
||||
elif self.settings.get("bridges_type") == "moat":
|
||||
for line in self.settings.get("bridges_moat").split("\n"):
|
||||
if line.strip() != "":
|
||||
f.write(f"Bridge {line}\n")
|
||||
f.write("\nUseBridges 1\n")
|
||||
|
||||
elif self.settings.get("tor_bridges_use_custom_bridges"):
|
||||
for line in self.settings.get(
|
||||
"tor_bridges_use_custom_bridges"
|
||||
).split("\n"):
|
||||
if line.strip() != "":
|
||||
f.write(f"Bridge {line}\n")
|
||||
f.write("\nUseBridges 1\n")
|
||||
elif self.settings.get("bridges_type") == "custom":
|
||||
for line in self.settings.get("bridges_custom").split("\n"):
|
||||
if line.strip() != "":
|
||||
f.write(f"Bridge {line}\n")
|
||||
f.write("\nUseBridges 1\n")
|
||||
|
||||
# Execute a tor subprocess
|
||||
start_ts = time.time()
|
||||
@ -421,11 +424,7 @@ class Onion(object):
|
||||
time.sleep(0.2)
|
||||
|
||||
# If using bridges, it might take a bit longer to connect to Tor
|
||||
if (
|
||||
self.settings.get("tor_bridges_use_custom_bridges")
|
||||
or self.settings.get("tor_bridges_use_obfs4")
|
||||
or self.settings.get("tor_bridges_use_meek_lite_azure")
|
||||
):
|
||||
if self.settings.get("bridges_enabled"):
|
||||
# Only override timeout if a custom timeout has not been passed in
|
||||
if connect_timeout == 120:
|
||||
connect_timeout = 150
|
||||
|
@ -105,13 +105,11 @@ class Settings(object):
|
||||
"auth_password": "",
|
||||
"use_autoupdate": True,
|
||||
"autoupdate_timestamp": None,
|
||||
"no_bridges": True,
|
||||
"tor_bridges_use_obfs4": False,
|
||||
"tor_bridges_use_meek_lite_azure": False,
|
||||
"tor_bridges_use_snowflake": False,
|
||||
"tor_bridges_use_moat": False,
|
||||
"tor_bridges_use_moat_bridges": "",
|
||||
"tor_bridges_use_custom_bridges": "",
|
||||
"bridges_enabled": False,
|
||||
"bridges_type": "built-in", # "built-in", "moat", or "custom"
|
||||
"bridges_builtin_pt": "obfs4", # "obfs4", "meek-azure", or "snowflake"
|
||||
"bridges_moat": "",
|
||||
"bridges_custom": "",
|
||||
"persistent_tabs": [],
|
||||
"locale": None, # this gets defined in fill_in_defaults()
|
||||
"theme": 0,
|
||||
|
@ -29,13 +29,11 @@ class TestSettings:
|
||||
"auth_password": "",
|
||||
"use_autoupdate": True,
|
||||
"autoupdate_timestamp": None,
|
||||
"no_bridges": True,
|
||||
"tor_bridges_use_obfs4": False,
|
||||
"tor_bridges_use_meek_lite_azure": False,
|
||||
"tor_bridges_use_snowflake": False,
|
||||
"tor_bridges_use_moat": False,
|
||||
"tor_bridges_use_moat_bridges": "",
|
||||
"tor_bridges_use_custom_bridges": "",
|
||||
"bridges_enabled": False,
|
||||
"bridges_type": "built-in",
|
||||
"bridges_builtin_pt": "obfs4",
|
||||
"bridges_moat": "",
|
||||
"bridges_custom": "",
|
||||
"persistent_tabs": [],
|
||||
"theme": 0,
|
||||
}
|
||||
@ -96,10 +94,11 @@ class TestSettings:
|
||||
assert settings_obj.get("use_autoupdate") is True
|
||||
assert settings_obj.get("autoupdate_timestamp") is None
|
||||
assert settings_obj.get("autoupdate_timestamp") is None
|
||||
assert settings_obj.get("no_bridges") is True
|
||||
assert settings_obj.get("tor_bridges_use_obfs4") is False
|
||||
assert settings_obj.get("tor_bridges_use_meek_lite_azure") is False
|
||||
assert settings_obj.get("tor_bridges_use_custom_bridges") == ""
|
||||
assert settings_obj.get("bridges_enabled") is False
|
||||
assert settings_obj.get("bridges_type") == "built-in"
|
||||
assert settings_obj.get("bridges_builtin_pt") == "obfs4"
|
||||
assert settings_obj.get("bridges_moat") == ""
|
||||
assert settings_obj.get("bridges_custom") == ""
|
||||
|
||||
def test_set_version(self, settings_obj):
|
||||
settings_obj.set("version", "CUSTOM_VERSION")
|
||||
@ -142,10 +141,10 @@ class TestSettings:
|
||||
|
||||
def test_set_custom_bridge(self, settings_obj):
|
||||
settings_obj.set(
|
||||
"tor_bridges_use_custom_bridges",
|
||||
"bridges_custom",
|
||||
"Bridge 45.3.20.65:9050 21300AD88890A49C429A6CB9959CFD44490A8F6E",
|
||||
)
|
||||
assert (
|
||||
settings_obj._settings["tor_bridges_use_custom_bridges"]
|
||||
settings_obj._settings["bridges_custom"]
|
||||
== "Bridge 45.3.20.65:9050 21300AD88890A49C429A6CB9959CFD44490A8F6E"
|
||||
)
|
||||
|
@ -65,7 +65,7 @@ python scripts\get-tor-windows.py
|
||||
|
||||
### Compile dependencies
|
||||
|
||||
Install Go. The simplest way to make sure everything works is to install Go by following [these instructions](https://golang.org/doc/install).
|
||||
Install Go. The simplest way to make sure everything works is to install Go by following [these instructions](https://golang.org/doc/install). (In Windows, make sure to install the 32-bit version of Go, such as `go1.17.3.windows-386.msi`.)
|
||||
|
||||
Download and compile `meek-client`:
|
||||
|
||||
|
@ -28,6 +28,7 @@ import shutil
|
||||
import os
|
||||
import subprocess
|
||||
import inspect
|
||||
import platform
|
||||
|
||||
|
||||
def main():
|
||||
@ -46,16 +47,21 @@ def main():
|
||||
root_path = os.path.dirname(
|
||||
os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
|
||||
)
|
||||
dist_path = os.path.join(root_path, "src", "onionshare", "resources", "tor")
|
||||
if platform.system() == "Windows":
|
||||
dist_path = os.path.join(root_path, "src", "onionshare", "resources", "tor", "Tor")
|
||||
bin_filename = "meek-client.exe"
|
||||
else:
|
||||
dist_path = os.path.join(root_path, "src", "onionshare", "resources", "tor")
|
||||
bin_filename = "meek-client"
|
||||
|
||||
bin_path = os.path.expanduser("~/go/bin/meek-client")
|
||||
bin_path = os.path.join(os.path.expanduser("~"), "go", "bin", bin_filename)
|
||||
shutil.copyfile(
|
||||
os.path.join(bin_path),
|
||||
os.path.join(dist_path, "meek-client"),
|
||||
os.path.join(dist_path, bin_filename),
|
||||
)
|
||||
os.chmod(os.path.join(dist_path, "meek-client"), 0o755)
|
||||
os.chmod(os.path.join(dist_path, bin_filename), 0o755)
|
||||
|
||||
print(f"Installed meek-client in {dist_path}")
|
||||
print(f"Installed {bin_filename} in {dist_path}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@ -34,10 +34,10 @@ import requests
|
||||
|
||||
|
||||
def main():
|
||||
tarball_url = "https://dist.torproject.org/torbrowser/11.0a9/tor-browser-linux64-11.0a9_en-US.tar.xz"
|
||||
tarball_filename = "tor-browser-linux64-11.0a9_en-US.tar.xz"
|
||||
tarball_url = "https://dist.torproject.org/torbrowser/11.0a10/tor-browser-linux64-11.0a10_en-US.tar.xz"
|
||||
tarball_filename = "tor-browser-linux64-11.0a10_en-US.tar.xz"
|
||||
expected_tarball_sha256 = (
|
||||
"cba4a2120b4f847d1ade637e41e69bd01b2e70b4a13e41fe8e69d0424fcf7ca7"
|
||||
"5d3e2ebc4fb6a10f44624359bc2a5a151a57e8402cbd8563d15f9b2524374f1f"
|
||||
)
|
||||
|
||||
# Build paths
|
||||
|
@ -34,10 +34,10 @@ import requests
|
||||
|
||||
|
||||
def main():
|
||||
dmg_url = "https://dist.torproject.org/torbrowser/11.0a7/TorBrowser-11.0a7-osx64_en-US.dmg"
|
||||
dmg_filename = "TorBrowser-11.0a7-osx64_en-US.dmg"
|
||||
dmg_url = "https://dist.torproject.org/torbrowser/11.0a10/TorBrowser-11.0a10-osx64_en-US.dmg"
|
||||
dmg_filename = "TorBrowser-11.0a10-osx64_en-US.dmg"
|
||||
expected_dmg_sha256 = (
|
||||
"46594cefa29493150d1c0e1933dd656aafcb6b51ef310d44ac059eed2fd1388e"
|
||||
"c6823a28fd28205437564815f93011ff93b7972da2a8ce16919adfc65909e7b9"
|
||||
)
|
||||
|
||||
# Build paths
|
||||
@ -101,6 +101,14 @@ def main():
|
||||
os.path.join(dist_path, "obfs4proxy"),
|
||||
)
|
||||
os.chmod(os.path.join(dist_path, "obfs4proxy"), 0o755)
|
||||
# snowflake-client binary
|
||||
shutil.copyfile(
|
||||
os.path.join(
|
||||
dmg_tor_path, "MacOS", "Tor", "PluggableTransports", "snowflake-client"
|
||||
),
|
||||
os.path.join(dist_path, "snowflake-client"),
|
||||
)
|
||||
os.chmod(os.path.join(dist_path, "snowflake-client"), 0o755)
|
||||
|
||||
# Eject dmg
|
||||
subprocess.call(["diskutil", "eject", "/Volumes/Tor Browser"])
|
||||
|
@ -33,10 +33,10 @@ import requests
|
||||
|
||||
|
||||
def main():
|
||||
exe_url = "https://dist.torproject.org/torbrowser/11.0a7/torbrowser-install-11.0a7_en-US.exe"
|
||||
exe_filename = "torbrowser-install-11.0a7_en-US.exe"
|
||||
exe_url = "https://dist.torproject.org/torbrowser/11.0a10/torbrowser-install-11.0a10_en-US.exe"
|
||||
exe_filename = "torbrowser-install-11.0a10_en-US.exe"
|
||||
expected_exe_sha256 = (
|
||||
"8b2013669d88e3ae8fa9bc17a3495eaac9475f79a849354e826e5132811a860b"
|
||||
"f567dd8368dea0a8d7bbf7c19ece7840f93d493e70662939b92f5058c8dc8d2d"
|
||||
)
|
||||
# Build paths
|
||||
root_path = os.path.dirname(
|
||||
|
@ -93,6 +93,7 @@ class GuiCommon:
|
||||
share_zip_progess_bar_chunk_color = "#4E064F"
|
||||
history_background_color = "#ffffff"
|
||||
history_label_color = "#000000"
|
||||
settings_error_color = "#FF0000"
|
||||
if color_mode == "dark":
|
||||
header_color = "#F2F2F2"
|
||||
title_color = "#F2F2F2"
|
||||
@ -103,6 +104,7 @@ class GuiCommon:
|
||||
share_zip_progess_bar_border_color = "#F2F2F2"
|
||||
history_background_color = "#191919"
|
||||
history_label_color = "#ffffff"
|
||||
settings_error_color = "#FF9999"
|
||||
|
||||
return {
|
||||
# OnionShareGui styles
|
||||
@ -281,6 +283,11 @@ class GuiCommon:
|
||||
QLabel {
|
||||
color: #cc0000;
|
||||
}""",
|
||||
"tor_not_connected_label": """
|
||||
QLabel {
|
||||
font-size: 16px;
|
||||
font-style: italic;
|
||||
}""",
|
||||
# New tab
|
||||
"new_tab_button_image": """
|
||||
QLabel {
|
||||
@ -392,10 +399,12 @@ class GuiCommon:
|
||||
QPushButton {
|
||||
padding: 5px 10px;
|
||||
}""",
|
||||
# Moat dialog
|
||||
"moat_error": """
|
||||
# Tor Settings dialogs
|
||||
"tor_settings_error": """
|
||||
QLabel {
|
||||
color: #990000;
|
||||
color: """
|
||||
+ settings_error_color
|
||||
+ """;
|
||||
}
|
||||
""",
|
||||
}
|
||||
|
@ -23,9 +23,7 @@ import time
|
||||
from PySide2 import QtCore, QtWidgets, QtGui
|
||||
|
||||
from . import strings
|
||||
from .tor_connection_dialog import TorConnectionDialog
|
||||
from .tor_settings_dialog import TorSettingsDialog
|
||||
from .settings_dialog import SettingsDialog
|
||||
from .tor_connection import TorConnectionDialog
|
||||
from .widgets import Alert
|
||||
from .update_checker import UpdateThread
|
||||
from .tab_widget import TabWidget
|
||||
@ -245,21 +243,17 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||
|
||||
def open_tor_settings(self):
|
||||
"""
|
||||
Open the TorSettingsDialog.
|
||||
Open the TorSettingsTab
|
||||
"""
|
||||
self.common.log("MainWindow", "open_tor_settings")
|
||||
d = TorSettingsDialog(self.common)
|
||||
d.settings_saved.connect(self.settings_have_changed)
|
||||
d.exec_()
|
||||
self.tabs.open_tor_settings_tab()
|
||||
|
||||
def open_settings(self):
|
||||
"""
|
||||
Open the SettingsDialog.
|
||||
Open the SettingsTab
|
||||
"""
|
||||
self.common.log("MainWindow", "open_settings")
|
||||
d = SettingsDialog(self.common)
|
||||
d.settings_saved.connect(self.settings_have_changed)
|
||||
d.exec_()
|
||||
self.tabs.open_settings_tab()
|
||||
|
||||
def settings_have_changed(self):
|
||||
self.common.log("OnionShareGui", "settings_have_changed")
|
||||
|
@ -26,7 +26,7 @@ import json
|
||||
|
||||
from . import strings
|
||||
from .gui_common import GuiCommon
|
||||
from onionshare_cli.meek import MeekNotFound
|
||||
from onionshare_cli.meek import MeekNotFound, MeekNotRunning
|
||||
|
||||
|
||||
class MoatDialog(QtWidgets.QDialog):
|
||||
@ -70,7 +70,7 @@ class MoatDialog(QtWidgets.QDialog):
|
||||
|
||||
# Error label
|
||||
self.error_label = QtWidgets.QLabel()
|
||||
self.error_label.setStyleSheet(self.common.gui.css["moat_error"])
|
||||
self.error_label.setStyleSheet(self.common.gui.css["tor_settings_error"])
|
||||
self.error_label.hide()
|
||||
|
||||
# Buttons
|
||||
@ -237,7 +237,13 @@ class MoatThread(QtCore.QThread):
|
||||
try:
|
||||
self.meek.start()
|
||||
except MeekNotFound:
|
||||
self.common.log("MoatThread", "run", f"Could not find the Meek Client")
|
||||
self.common.log("MoatThread", "run", f"Could not find meek-client")
|
||||
self.bridgedb_error.emit()
|
||||
return
|
||||
except MeekNotRunning:
|
||||
self.common.log(
|
||||
"MoatThread", "run", f"Ran meek-client, but there was an error"
|
||||
)
|
||||
self.bridgedb_error.emit()
|
||||
return
|
||||
|
||||
|
@ -71,7 +71,8 @@
|
||||
"gui_settings_bridge_custom_radio_option": "Provide a bridge you learned about from a trusted source",
|
||||
"gui_settings_bridge_custom_placeholder": "type address:port (one per line)",
|
||||
"gui_settings_moat_bridges_invalid": "You have not requested a bridge from torproject.org yet.",
|
||||
"gui_settings_tor_bridges_invalid": "None of the bridges you added work.\nDouble-check them or add others.",
|
||||
"gui_settings_tor_bridges_invalid": "None of the bridges you added work. Double-check them or add others.",
|
||||
"gui_settings_stop_active_tabs_label": "There are services running in some of your tabs.\nYou must stop all services to change your Tor settings.",
|
||||
"gui_settings_button_save": "Save",
|
||||
"gui_settings_button_cancel": "Cancel",
|
||||
"gui_settings_button_help": "Help",
|
||||
@ -228,5 +229,6 @@
|
||||
"moat_captcha_reload": "Reload",
|
||||
"moat_bridgedb_error": "Error contacting BridgeDB.",
|
||||
"moat_captcha_error": "The solution is not correct. Please try again.",
|
||||
"moat_solution_empty_error": "You must enter the characters from the image"
|
||||
"moat_solution_empty_error": "You must enter the characters from the image",
|
||||
"mode_tor_not_connected_label": "OnionShare is not connected to the Tor network"
|
||||
}
|
@ -19,57 +19,30 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
from PySide2 import QtCore, QtWidgets, QtGui
|
||||
from PySide2.QtCore import Slot, Qt
|
||||
from PySide2.QtGui import QPalette, QColor
|
||||
import sys
|
||||
import platform
|
||||
import datetime
|
||||
import re
|
||||
import os
|
||||
from onionshare_cli.settings import Settings
|
||||
from onionshare_cli.onion import (
|
||||
Onion,
|
||||
TorErrorInvalidSetting,
|
||||
TorErrorAutomatic,
|
||||
TorErrorSocketPort,
|
||||
TorErrorSocketFile,
|
||||
TorErrorMissingPassword,
|
||||
TorErrorUnreadableCookieFile,
|
||||
TorErrorAuthError,
|
||||
TorErrorProtocolError,
|
||||
BundledTorTimeout,
|
||||
BundledTorBroken,
|
||||
TorTooOldEphemeral,
|
||||
TorTooOldStealth,
|
||||
PortNotAvailable,
|
||||
)
|
||||
|
||||
from . import strings
|
||||
from .widgets import Alert
|
||||
from .update_checker import UpdateThread
|
||||
from .tor_connection_dialog import TorConnectionDialog
|
||||
from .gui_common import GuiCommon
|
||||
|
||||
|
||||
class SettingsDialog(QtWidgets.QDialog):
|
||||
class SettingsTab(QtWidgets.QWidget):
|
||||
"""
|
||||
Settings dialog.
|
||||
"""
|
||||
|
||||
settings_saved = QtCore.Signal()
|
||||
close_this_tab = QtCore.Signal()
|
||||
|
||||
def __init__(self, common):
|
||||
super(SettingsDialog, self).__init__()
|
||||
def __init__(self, common, tab_id):
|
||||
super(SettingsTab, self).__init__()
|
||||
|
||||
self.common = common
|
||||
|
||||
self.common.log("SettingsDialog", "__init__")
|
||||
|
||||
self.setModal(True)
|
||||
self.setWindowTitle(strings._("gui_settings_window_title"))
|
||||
self.setWindowIcon(QtGui.QIcon(GuiCommon.get_resource_path("images/logo.png")))
|
||||
self.common.log("SettingsTab", "__init__")
|
||||
|
||||
self.system = platform.system()
|
||||
self.tab_id = tab_id
|
||||
|
||||
# Automatic updates options
|
||||
|
||||
@ -100,9 +73,16 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
)
|
||||
autoupdate_group.setLayout(autoupdate_group_layout)
|
||||
|
||||
autoupdate_layout = QtWidgets.QHBoxLayout()
|
||||
autoupdate_layout.addStretch()
|
||||
autoupdate_layout.addWidget(autoupdate_group)
|
||||
autoupdate_layout.addStretch()
|
||||
autoupdate_widget = QtWidgets.QWidget()
|
||||
autoupdate_widget.setLayout(autoupdate_layout)
|
||||
|
||||
# Autoupdate is only available for Windows and Mac (Linux updates using package manager)
|
||||
if self.system != "Windows" and self.system != "Darwin":
|
||||
autoupdate_group.hide()
|
||||
autoupdate_widget.hide()
|
||||
|
||||
# Language settings
|
||||
language_label = QtWidgets.QLabel(strings._("gui_settings_language_label"))
|
||||
@ -117,6 +97,7 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
locale = language_names_to_locales[language_name]
|
||||
self.language_combobox.addItem(language_name, locale)
|
||||
language_layout = QtWidgets.QHBoxLayout()
|
||||
language_layout.addStretch()
|
||||
language_layout.addWidget(language_label)
|
||||
language_layout.addWidget(self.language_combobox)
|
||||
language_layout.addStretch()
|
||||
@ -131,6 +112,7 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
]
|
||||
self.theme_combobox.addItems(theme_choices)
|
||||
theme_layout = QtWidgets.QHBoxLayout()
|
||||
theme_layout.addStretch()
|
||||
theme_layout.addWidget(theme_label)
|
||||
theme_layout.addWidget(self.theme_combobox)
|
||||
theme_layout.addStretch()
|
||||
@ -139,41 +121,44 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
version_label = QtWidgets.QLabel(
|
||||
strings._("gui_settings_version_label").format(self.common.version)
|
||||
)
|
||||
version_label.setAlignment(QtCore.Qt.AlignHCenter)
|
||||
help_label = QtWidgets.QLabel(strings._("gui_settings_help_label"))
|
||||
help_label.setAlignment(QtCore.Qt.AlignHCenter)
|
||||
help_label.setTextInteractionFlags(QtCore.Qt.TextBrowserInteraction)
|
||||
help_label.setOpenExternalLinks(True)
|
||||
|
||||
# Buttons
|
||||
self.save_button = QtWidgets.QPushButton(strings._("gui_settings_button_save"))
|
||||
self.save_button.clicked.connect(self.save_clicked)
|
||||
self.cancel_button = QtWidgets.QPushButton(
|
||||
strings._("gui_settings_button_cancel")
|
||||
)
|
||||
self.cancel_button.clicked.connect(self.cancel_clicked)
|
||||
buttons_layout = QtWidgets.QHBoxLayout()
|
||||
buttons_layout.addStretch()
|
||||
buttons_layout.addWidget(self.save_button)
|
||||
buttons_layout.addWidget(self.cancel_button)
|
||||
buttons_layout.addStretch()
|
||||
|
||||
# Layout
|
||||
layout = QtWidgets.QVBoxLayout()
|
||||
layout.addWidget(autoupdate_group)
|
||||
if autoupdate_group.isVisible():
|
||||
layout.addStretch()
|
||||
layout.addWidget(autoupdate_widget)
|
||||
if autoupdate_widget.isVisible():
|
||||
layout.addSpacing(20)
|
||||
layout.addLayout(language_layout)
|
||||
layout.addLayout(theme_layout)
|
||||
layout.addSpacing(20)
|
||||
layout.addStretch()
|
||||
layout.addWidget(version_label)
|
||||
layout.addWidget(help_label)
|
||||
layout.addSpacing(20)
|
||||
layout.addLayout(buttons_layout)
|
||||
layout.addStretch()
|
||||
|
||||
self.setLayout(layout)
|
||||
self.cancel_button.setFocus()
|
||||
|
||||
self.reload_settings()
|
||||
|
||||
if self.common.gui.onion.connected_to_tor:
|
||||
self.tor_is_connected()
|
||||
else:
|
||||
self.tor_is_disconnected()
|
||||
|
||||
def reload_settings(self):
|
||||
# Load settings, and fill them in
|
||||
self.old_settings = Settings(self.common)
|
||||
@ -199,7 +184,7 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
"""
|
||||
Check for Updates button clicked. Manually force an update check.
|
||||
"""
|
||||
self.common.log("SettingsDialog", "check_for_updates")
|
||||
self.common.log("SettingsTab", "check_for_updates")
|
||||
# Disable buttons
|
||||
self._disable_buttons()
|
||||
self.common.gui.qtapp.processEvents()
|
||||
@ -261,7 +246,7 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
"""
|
||||
Save button clicked. Save current settings to disk.
|
||||
"""
|
||||
self.common.log("SettingsDialog", "save_clicked")
|
||||
self.common.log("SettingsTab", "save_clicked")
|
||||
|
||||
def changed(s1, s2, keys):
|
||||
"""
|
||||
@ -298,33 +283,14 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
|
||||
# Save the new settings
|
||||
settings.save()
|
||||
self.settings_saved.emit()
|
||||
self.close()
|
||||
|
||||
def cancel_clicked(self):
|
||||
"""
|
||||
Cancel button clicked.
|
||||
"""
|
||||
self.common.log("SettingsDialog", "cancel_clicked")
|
||||
if (
|
||||
not self.common.gui.local_only
|
||||
and not self.common.gui.onion.is_authenticated()
|
||||
):
|
||||
Alert(
|
||||
self.common,
|
||||
strings._("gui_tor_connection_canceled"),
|
||||
QtWidgets.QMessageBox.Warning,
|
||||
)
|
||||
sys.exit()
|
||||
else:
|
||||
self.close()
|
||||
self.close_this_tab.emit()
|
||||
|
||||
def help_clicked(self):
|
||||
"""
|
||||
Help button clicked.
|
||||
"""
|
||||
self.common.log("SettingsDialog", "help_clicked")
|
||||
SettingsDialog.open_help()
|
||||
self.common.log("SettingsTab", "help_clicked")
|
||||
SettingsTab.open_help()
|
||||
|
||||
@staticmethod
|
||||
def open_help():
|
||||
@ -335,7 +301,7 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
"""
|
||||
Return a Settings object that's full of values from the settings dialog.
|
||||
"""
|
||||
self.common.log("SettingsDialog", "settings_from_fields")
|
||||
self.common.log("SettingsTab", "settings_from_fields")
|
||||
settings = Settings(self.common)
|
||||
settings.load() # To get the last update timestamp
|
||||
|
||||
@ -350,8 +316,12 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
|
||||
return settings
|
||||
|
||||
def settings_have_changed(self):
|
||||
# Global settings have changed
|
||||
self.common.log("SettingsTab", "settings_have_changed")
|
||||
|
||||
def _update_autoupdate_timestamp(self, autoupdate_timestamp):
|
||||
self.common.log("SettingsDialog", "_update_autoupdate_timestamp")
|
||||
self.common.log("SettingsTab", "_update_autoupdate_timestamp")
|
||||
|
||||
if autoupdate_timestamp:
|
||||
dt = datetime.datetime.fromtimestamp(autoupdate_timestamp)
|
||||
@ -363,18 +333,22 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
)
|
||||
|
||||
def _disable_buttons(self):
|
||||
self.common.log("SettingsDialog", "_disable_buttons")
|
||||
self.common.log("SettingsTab", "_disable_buttons")
|
||||
|
||||
self.check_for_updates_button.setEnabled(False)
|
||||
self.save_button.setEnabled(False)
|
||||
self.cancel_button.setEnabled(False)
|
||||
|
||||
def _enable_buttons(self):
|
||||
self.common.log("SettingsDialog", "_enable_buttons")
|
||||
self.common.log("SettingsTab", "_enable_buttons")
|
||||
# We can't check for updates if we're still not connected to Tor
|
||||
if not self.common.gui.onion.connected_to_tor:
|
||||
self.check_for_updates_button.setEnabled(False)
|
||||
else:
|
||||
self.check_for_updates_button.setEnabled(True)
|
||||
self.save_button.setEnabled(True)
|
||||
self.cancel_button.setEnabled(True)
|
||||
|
||||
def tor_is_connected(self):
|
||||
self.check_for_updates_button.show()
|
||||
|
||||
def tor_is_disconnected(self):
|
||||
self.check_for_updates_button.hide()
|
@ -28,7 +28,7 @@ from .mode_settings_widget import ModeSettingsWidget
|
||||
from ..server_status import ServerStatus
|
||||
from ... import strings
|
||||
from ...threads import OnionThread, AutoStartTimer
|
||||
from ...widgets import Alert
|
||||
from ...widgets import Alert, MinimumSizeWidget
|
||||
|
||||
|
||||
class Mode(QtWidgets.QWidget):
|
||||
@ -101,6 +101,38 @@ class Mode(QtWidgets.QWidget):
|
||||
self.primary_action = QtWidgets.QWidget()
|
||||
self.primary_action.setLayout(self.primary_action_layout)
|
||||
|
||||
# It's up to the downstream Mode to add stuff to self.content_layout
|
||||
# self.content_layout shows the actual content of the mode
|
||||
# self.tor_not_connected_layout is displayed when Tor isn't connected
|
||||
self.content_layout = QtWidgets.QVBoxLayout()
|
||||
self.content_widget = QtWidgets.QWidget()
|
||||
self.content_widget.setLayout(self.content_layout)
|
||||
|
||||
tor_not_connected_label = QtWidgets.QLabel(
|
||||
strings._("mode_tor_not_connected_label")
|
||||
)
|
||||
tor_not_connected_label.setAlignment(QtCore.Qt.AlignHCenter)
|
||||
tor_not_connected_label.setStyleSheet(
|
||||
self.common.gui.css["tor_not_connected_label"]
|
||||
)
|
||||
self.tor_not_connected_layout = QtWidgets.QVBoxLayout()
|
||||
self.tor_not_connected_layout.addStretch()
|
||||
self.tor_not_connected_layout.addWidget(tor_not_connected_label)
|
||||
self.tor_not_connected_layout.addWidget(MinimumSizeWidget(700, 0))
|
||||
self.tor_not_connected_layout.addStretch()
|
||||
self.tor_not_connected_widget = QtWidgets.QWidget()
|
||||
self.tor_not_connected_widget.setLayout(self.tor_not_connected_layout)
|
||||
|
||||
self.wrapper_layout = QtWidgets.QVBoxLayout()
|
||||
self.wrapper_layout.addWidget(self.content_widget)
|
||||
self.wrapper_layout.addWidget(self.tor_not_connected_widget)
|
||||
self.setLayout(self.wrapper_layout)
|
||||
|
||||
if self.common.gui.onion.connected_to_tor:
|
||||
self.tor_connection_started()
|
||||
else:
|
||||
self.tor_connection_stopped()
|
||||
|
||||
def init(self):
|
||||
"""
|
||||
Add custom initialization here.
|
||||
@ -524,3 +556,21 @@ class Mode(QtWidgets.QWidget):
|
||||
Used in both Share and Website modes, so implemented here.
|
||||
"""
|
||||
self.history.cancel(event["data"]["id"])
|
||||
|
||||
def tor_connection_started(self):
|
||||
"""
|
||||
This is called on every Mode when Tor is connected
|
||||
"""
|
||||
self.content_widget.show()
|
||||
self.tor_not_connected_widget.hide()
|
||||
|
||||
def tor_connection_stopped(self):
|
||||
"""
|
||||
This is called on every Mode when Tor is disconnected
|
||||
"""
|
||||
if self.common.gui.local_only:
|
||||
self.tor_connection_started()
|
||||
return
|
||||
|
||||
self.content_widget.hide()
|
||||
self.tor_not_connected_widget.show()
|
||||
|
@ -98,10 +98,8 @@ class ChatMode(Mode):
|
||||
self.column_layout.addWidget(self.image)
|
||||
self.column_layout.addLayout(self.main_layout)
|
||||
|
||||
# Wrapper layout
|
||||
self.wrapper_layout = QtWidgets.QVBoxLayout()
|
||||
self.wrapper_layout.addLayout(self.column_layout)
|
||||
self.setLayout(self.wrapper_layout)
|
||||
# Content layout
|
||||
self.content_layout.addLayout(self.column_layout)
|
||||
|
||||
def get_type(self):
|
||||
"""
|
||||
|
@ -198,10 +198,8 @@ class ReceiveMode(Mode):
|
||||
self.column_layout.addLayout(row_layout)
|
||||
self.column_layout.addWidget(self.history, stretch=1)
|
||||
|
||||
# Wrapper layout
|
||||
self.wrapper_layout = QtWidgets.QVBoxLayout()
|
||||
self.wrapper_layout.addLayout(self.column_layout)
|
||||
self.setLayout(self.wrapper_layout)
|
||||
# Content layout
|
||||
self.content_layout.addLayout(self.column_layout)
|
||||
|
||||
def get_type(self):
|
||||
"""
|
||||
|
@ -169,10 +169,8 @@ class ShareMode(Mode):
|
||||
self.column_layout.addLayout(self.main_layout)
|
||||
self.column_layout.addWidget(self.history, stretch=1)
|
||||
|
||||
# Wrapper layout
|
||||
self.wrapper_layout = QtWidgets.QVBoxLayout()
|
||||
self.wrapper_layout.addLayout(self.column_layout)
|
||||
self.setLayout(self.wrapper_layout)
|
||||
# Content layout
|
||||
self.content_layout.addLayout(self.column_layout)
|
||||
|
||||
# Always start with focus on file selection
|
||||
self.file_selection.setFocus()
|
||||
|
@ -167,10 +167,8 @@ class WebsiteMode(Mode):
|
||||
self.column_layout.addLayout(self.main_layout)
|
||||
self.column_layout.addWidget(self.history, stretch=1)
|
||||
|
||||
# Wrapper layout
|
||||
self.wrapper_layout = QtWidgets.QVBoxLayout()
|
||||
self.wrapper_layout.addLayout(self.column_layout)
|
||||
self.setLayout(self.wrapper_layout)
|
||||
# Content layout
|
||||
self.content_layout.addLayout(self.column_layout)
|
||||
|
||||
# Always start with focus on file selection
|
||||
self.file_selection.setFocus()
|
||||
|
@ -96,7 +96,6 @@ class Tab(QtWidgets.QWidget):
|
||||
tab_id,
|
||||
system_tray,
|
||||
status_bar,
|
||||
mode_settings=None,
|
||||
filenames=None,
|
||||
):
|
||||
super(Tab, self).__init__()
|
||||
|
@ -26,6 +26,8 @@ from . import strings
|
||||
from .tab import Tab
|
||||
from .threads import EventHandlerThread
|
||||
from .gui_common import GuiCommon
|
||||
from .tor_settings_tab import TorSettingsTab
|
||||
from .settings_tab import SettingsTab
|
||||
|
||||
|
||||
class TabWidget(QtWidgets.QTabWidget):
|
||||
@ -43,9 +45,12 @@ class TabWidget(QtWidgets.QTabWidget):
|
||||
self.system_tray = system_tray
|
||||
self.status_bar = status_bar
|
||||
|
||||
# Keep track of tabs in a dictionary
|
||||
# Keep track of tabs in a dictionary that maps tab_id to tab.
|
||||
# Each tab has a unique, auto-incremented id (tab_id). This is different than the
|
||||
# tab's index, which changes as tabs are re-arranged.
|
||||
self.tabs = {}
|
||||
self.current_tab_id = 0 # Each tab has a unique id
|
||||
self.tor_settings_tab = None
|
||||
|
||||
# Define the new tab button
|
||||
self.new_tab_button = QtWidgets.QPushButton("+", parent=self)
|
||||
@ -89,9 +94,12 @@ class TabWidget(QtWidgets.QTabWidget):
|
||||
self.event_handler_t.wait(50)
|
||||
|
||||
# Clean up each tab
|
||||
for index in range(self.count()):
|
||||
tab = self.widget(index)
|
||||
tab.cleanup()
|
||||
for tab_id in self.tabs:
|
||||
if not (
|
||||
type(self.tabs[tab_id]) is SettingsTab
|
||||
or type(self.tabs[tab_id]) is TorSettingsTab
|
||||
):
|
||||
self.tabs[tab_id].cleanup()
|
||||
|
||||
def move_new_tab_button(self):
|
||||
# Find the width of all tabs
|
||||
@ -114,8 +122,28 @@ class TabWidget(QtWidgets.QTabWidget):
|
||||
|
||||
def tab_changed(self):
|
||||
# Active tab was changed
|
||||
tab_id = self.currentIndex()
|
||||
tab = self.widget(self.currentIndex())
|
||||
if not tab:
|
||||
self.common.log(
|
||||
"TabWidget",
|
||||
"tab_changed",
|
||||
f"tab at index {self.currentIndex()} does not exist",
|
||||
)
|
||||
return
|
||||
|
||||
tab_id = tab.tab_id
|
||||
self.common.log("TabWidget", "tab_changed", f"Tab was changed to {tab_id}")
|
||||
|
||||
# If it's Settings or Tor Settings, ignore
|
||||
if (
|
||||
type(self.tabs[tab_id]) is SettingsTab
|
||||
or type(self.tabs[tab_id]) is TorSettingsTab
|
||||
):
|
||||
# Blank the server status indicator
|
||||
self.status_bar.server_status_image_label.clear()
|
||||
self.status_bar.server_status_label.clear()
|
||||
return
|
||||
|
||||
try:
|
||||
mode = self.tabs[tab_id].get_mode()
|
||||
if mode:
|
||||
@ -158,23 +186,6 @@ class TabWidget(QtWidgets.QTabWidget):
|
||||
index = self.addTab(tab, strings._("gui_new_tab"))
|
||||
self.setCurrentIndex(index)
|
||||
|
||||
# In macOS, manually create a close button because tabs don't seem to have them otherwise
|
||||
if self.common.platform == "Darwin":
|
||||
|
||||
def close_tab():
|
||||
self.tabBar().tabCloseRequested.emit(self.indexOf(tab))
|
||||
|
||||
tab.close_button = QtWidgets.QPushButton()
|
||||
tab.close_button.setFlat(True)
|
||||
tab.close_button.setFixedWidth(40)
|
||||
tab.close_button.setIcon(
|
||||
QtGui.QIcon(GuiCommon.get_resource_path("images/close_tab.png"))
|
||||
)
|
||||
tab.close_button.clicked.connect(close_tab)
|
||||
self.tabBar().setTabButton(
|
||||
index, QtWidgets.QTabBar.RightSide, tab.close_button
|
||||
)
|
||||
|
||||
tab.init(mode_settings)
|
||||
|
||||
# Make sure the title is set
|
||||
@ -187,6 +198,44 @@ class TabWidget(QtWidgets.QTabWidget):
|
||||
# Bring the window to front, in case this is being added by an event
|
||||
self.bring_to_front.emit()
|
||||
|
||||
def open_settings_tab(self):
|
||||
self.common.log("TabWidget", "open_settings_tab")
|
||||
|
||||
# See if a settings tab is already open, and if so switch to it
|
||||
for tab_id in self.tabs:
|
||||
if type(self.tabs[tab_id]) is SettingsTab:
|
||||
self.setCurrentIndex(self.indexOf(self.tabs[tab_id]))
|
||||
return
|
||||
|
||||
settings_tab = SettingsTab(self.common, self.current_tab_id)
|
||||
settings_tab.close_this_tab.connect(self.close_settings_tab)
|
||||
self.tabs[self.current_tab_id] = settings_tab
|
||||
self.current_tab_id += 1
|
||||
index = self.addTab(settings_tab, strings._("gui_settings_window_title"))
|
||||
self.setCurrentIndex(index)
|
||||
|
||||
def open_tor_settings_tab(self):
|
||||
self.common.log("TabWidget", "open_tor_settings_tab")
|
||||
|
||||
# See if a settings tab is already open, and if so switch to it
|
||||
for tab_id in self.tabs:
|
||||
if type(self.tabs[tab_id]) is TorSettingsTab:
|
||||
self.setCurrentIndex(self.indexOf(self.tabs[tab_id]))
|
||||
return
|
||||
|
||||
self.tor_settings_tab = TorSettingsTab(
|
||||
self.common, self.current_tab_id, self.are_tabs_active(), self.status_bar
|
||||
)
|
||||
self.tor_settings_tab.close_this_tab.connect(self.close_tor_settings_tab)
|
||||
self.tor_settings_tab.tor_is_connected.connect(self.tor_is_connected)
|
||||
self.tor_settings_tab.tor_is_disconnected.connect(self.tor_is_disconnected)
|
||||
self.tabs[self.current_tab_id] = self.tor_settings_tab
|
||||
self.current_tab_id += 1
|
||||
index = self.addTab(
|
||||
self.tor_settings_tab, strings._("gui_tor_settings_window_title")
|
||||
)
|
||||
self.setCurrentIndex(index)
|
||||
|
||||
def change_title(self, tab_id, title):
|
||||
shortened_title = title
|
||||
if len(shortened_title) > 11:
|
||||
@ -200,6 +249,11 @@ class TabWidget(QtWidgets.QTabWidget):
|
||||
index = self.indexOf(self.tabs[tab_id])
|
||||
self.setTabIcon(index, QtGui.QIcon(GuiCommon.get_resource_path(icon_path)))
|
||||
|
||||
# The icon changes when the server status changes, so if we have an open
|
||||
# Tor Settings tab, tell it to update
|
||||
if self.tor_settings_tab:
|
||||
self.tor_settings_tab.active_tabs_changed(self.are_tabs_active())
|
||||
|
||||
def change_persistent(self, tab_id, is_persistent):
|
||||
self.common.log(
|
||||
"TabWidget",
|
||||
@ -223,10 +277,14 @@ class TabWidget(QtWidgets.QTabWidget):
|
||||
def save_persistent_tabs(self):
|
||||
# Figure out the order of persistent tabs to save in settings
|
||||
persistent_tabs = []
|
||||
for index in range(self.count()):
|
||||
tab = self.widget(index)
|
||||
if tab.settings.get("persistent", "enabled"):
|
||||
persistent_tabs.append(tab.settings.id)
|
||||
for tab_id in self.tabs:
|
||||
if not (
|
||||
type(self.tabs[tab_id]) is SettingsTab
|
||||
or type(self.tabs[tab_id]) is TorSettingsTab
|
||||
):
|
||||
tab = self.widget(self.indexOf(self.tabs[tab_id]))
|
||||
if tab.settings.get("persistent", "enabled"):
|
||||
persistent_tabs.append(tab.settings.id)
|
||||
# Only save if tabs have actually moved
|
||||
if persistent_tabs != self.common.settings.get("persistent_tabs"):
|
||||
self.common.settings.set("persistent_tabs", persistent_tabs)
|
||||
@ -235,10 +293,16 @@ class TabWidget(QtWidgets.QTabWidget):
|
||||
def close_tab(self, index):
|
||||
self.common.log("TabWidget", "close_tab", f"{index}")
|
||||
tab = self.widget(index)
|
||||
if tab.close_tab():
|
||||
# If the tab is persistent, delete the settings file from disk
|
||||
if tab.settings.get("persistent", "enabled"):
|
||||
tab.settings.delete()
|
||||
tab_id = tab.tab_id
|
||||
|
||||
if (
|
||||
type(self.tabs[tab_id]) is SettingsTab
|
||||
or type(self.tabs[tab_id]) is TorSettingsTab
|
||||
):
|
||||
self.common.log("TabWidget", "closing a settings tab")
|
||||
|
||||
if type(self.tabs[tab_id]) is TorSettingsTab:
|
||||
self.tor_settings_tab = None
|
||||
|
||||
# Remove the tab
|
||||
self.removeTab(index)
|
||||
@ -248,17 +312,56 @@ class TabWidget(QtWidgets.QTabWidget):
|
||||
if self.count() == 0:
|
||||
self.new_tab_clicked()
|
||||
|
||||
self.save_persistent_tabs()
|
||||
else:
|
||||
self.common.log("TabWidget", "closing a service tab")
|
||||
if tab.close_tab():
|
||||
self.common.log("TabWidget", "user is okay with closing the tab")
|
||||
|
||||
# If the tab is persistent, delete the settings file from disk
|
||||
if tab.settings.get("persistent", "enabled"):
|
||||
tab.settings.delete()
|
||||
|
||||
self.save_persistent_tabs()
|
||||
|
||||
# Remove the tab
|
||||
self.removeTab(index)
|
||||
del self.tabs[tab.tab_id]
|
||||
|
||||
# If the last tab is closed, open a new one
|
||||
if self.count() == 0:
|
||||
self.new_tab_clicked()
|
||||
else:
|
||||
self.common.log("TabWidget", "user does not want to close the tab")
|
||||
|
||||
def close_settings_tab(self):
|
||||
self.common.log("TabWidget", "close_settings_tab")
|
||||
for tab_id in self.tabs:
|
||||
if type(self.tabs[tab_id]) is SettingsTab:
|
||||
index = self.indexOf(self.tabs[tab_id])
|
||||
self.close_tab(index)
|
||||
return
|
||||
|
||||
def close_tor_settings_tab(self):
|
||||
self.common.log("TabWidget", "close_tor_settings_tab")
|
||||
for tab_id in self.tabs:
|
||||
if type(self.tabs[tab_id]) is TorSettingsTab:
|
||||
index = self.indexOf(self.tabs[tab_id])
|
||||
self.close_tab(index)
|
||||
return
|
||||
|
||||
def are_tabs_active(self):
|
||||
"""
|
||||
See if there are active servers in any open tabs
|
||||
"""
|
||||
for tab_id in self.tabs:
|
||||
mode = self.tabs[tab_id].get_mode()
|
||||
if mode:
|
||||
if mode.server_status.status != mode.server_status.STATUS_STOPPED:
|
||||
return True
|
||||
if not (
|
||||
type(self.tabs[tab_id]) is SettingsTab
|
||||
or type(self.tabs[tab_id]) is TorSettingsTab
|
||||
):
|
||||
mode = self.tabs[tab_id].get_mode()
|
||||
if mode:
|
||||
if mode.server_status.status != mode.server_status.STATUS_STOPPED:
|
||||
return True
|
||||
return False
|
||||
|
||||
def paintEvent(self, event):
|
||||
@ -273,6 +376,26 @@ class TabWidget(QtWidgets.QTabWidget):
|
||||
super(TabWidget, self).resizeEvent(event)
|
||||
self.move_new_tab_button()
|
||||
|
||||
def tor_is_connected(self):
|
||||
for tab_id in self.tabs:
|
||||
if type(self.tabs[tab_id]) is SettingsTab:
|
||||
self.tabs[tab_id].tor_is_connected()
|
||||
else:
|
||||
if not type(self.tabs[tab_id]) is TorSettingsTab:
|
||||
mode = self.tabs[tab_id].get_mode()
|
||||
if mode:
|
||||
mode.tor_connection_started()
|
||||
|
||||
def tor_is_disconnected(self):
|
||||
for tab_id in self.tabs:
|
||||
if type(self.tabs[tab_id]) is SettingsTab:
|
||||
self.tabs[tab_id].tor_is_disconnected()
|
||||
else:
|
||||
if not type(self.tabs[tab_id]) is TorSettingsTab:
|
||||
mode = self.tabs[tab_id].get_mode()
|
||||
if mode:
|
||||
mode.tor_connection_stopped()
|
||||
|
||||
|
||||
class TabBar(QtWidgets.QTabBar):
|
||||
"""
|
||||
|
@ -117,7 +117,6 @@ class TorConnectionDialog(QtWidgets.QProgressDialog):
|
||||
def _connected_to_tor(self):
|
||||
self.common.log("TorConnectionDialog", "_connected_to_tor")
|
||||
self.active = False
|
||||
|
||||
# Close the dialog after connecting
|
||||
self.setValue(self.maximum())
|
||||
|
||||
@ -157,26 +156,136 @@ class TorConnectionDialog(QtWidgets.QProgressDialog):
|
||||
QtCore.QTimer.singleShot(1, self.cancel)
|
||||
|
||||
|
||||
class TorConnectionWidget(QtWidgets.QWidget):
|
||||
"""
|
||||
Connecting to Tor widget, with a progress bar
|
||||
"""
|
||||
|
||||
open_tor_settings = QtCore.Signal()
|
||||
success = QtCore.Signal()
|
||||
fail = QtCore.Signal(str)
|
||||
|
||||
def __init__(self, common, status_bar):
|
||||
super(TorConnectionWidget, self).__init__(None)
|
||||
self.common = common
|
||||
self.common.log("TorConnectionWidget", "__init__")
|
||||
|
||||
self.status_bar = status_bar
|
||||
self.label = QtWidgets.QLabel(strings._("connecting_to_tor"))
|
||||
self.label.setAlignment(QtCore.Qt.AlignHCenter)
|
||||
|
||||
self.progress = QtWidgets.QProgressBar()
|
||||
self.progress.setRange(0, 100)
|
||||
self.cancel_button = QtWidgets.QPushButton(
|
||||
strings._("gui_settings_button_cancel")
|
||||
)
|
||||
self.cancel_button.clicked.connect(self.cancel_clicked)
|
||||
|
||||
progress_layout = QtWidgets.QHBoxLayout()
|
||||
progress_layout.addWidget(self.progress)
|
||||
progress_layout.addWidget(self.cancel_button)
|
||||
|
||||
inner_layout = QtWidgets.QVBoxLayout()
|
||||
inner_layout.addWidget(self.label)
|
||||
inner_layout.addLayout(progress_layout)
|
||||
|
||||
layout = QtWidgets.QHBoxLayout()
|
||||
layout.addStretch()
|
||||
layout.addLayout(inner_layout)
|
||||
layout.addStretch()
|
||||
self.setLayout(layout)
|
||||
|
||||
# Start displaying the status at 0
|
||||
self._tor_status_update(0, "")
|
||||
|
||||
def start(self, custom_settings=False, testing_settings=False, onion=None):
|
||||
self.common.log("TorConnectionWidget", "start")
|
||||
self.was_canceled = False
|
||||
|
||||
self.testing_settings = testing_settings
|
||||
|
||||
if custom_settings:
|
||||
self.settings = custom_settings
|
||||
else:
|
||||
self.settings = self.common.settings
|
||||
|
||||
if self.testing_settings:
|
||||
self.onion = onion
|
||||
else:
|
||||
self.onion = self.common.gui.onion
|
||||
|
||||
t = TorConnectionThread(self.common, self.settings, self)
|
||||
t.tor_status_update.connect(self._tor_status_update)
|
||||
t.connected_to_tor.connect(self._connected_to_tor)
|
||||
t.canceled_connecting_to_tor.connect(self._canceled_connecting_to_tor)
|
||||
t.error_connecting_to_tor.connect(self._error_connecting_to_tor)
|
||||
t.start()
|
||||
|
||||
# The main thread needs to remain active, and checking for Qt events,
|
||||
# until the thread is finished. Otherwise it won't be able to handle
|
||||
# accepting signals.
|
||||
self.active = True
|
||||
while self.active:
|
||||
time.sleep(0.1)
|
||||
self.common.gui.qtapp.processEvents()
|
||||
|
||||
def cancel_clicked(self):
|
||||
self.was_canceled = True
|
||||
self.fail.emit("")
|
||||
|
||||
def wasCanceled(self):
|
||||
return self.was_canceled
|
||||
|
||||
def _tor_status_update(self, progress, summary):
|
||||
self.progress.setValue(int(progress))
|
||||
self.label.setText(
|
||||
f"<strong>{strings._('connecting_to_tor')}</strong><br>{summary}"
|
||||
)
|
||||
|
||||
def _connected_to_tor(self):
|
||||
self.common.log("TorConnectionWidget", "_connected_to_tor")
|
||||
self.active = False
|
||||
self.status_bar.clearMessage()
|
||||
|
||||
# Close the dialog after connecting
|
||||
self.progress.setValue(self.progress.maximum())
|
||||
|
||||
self.success.emit()
|
||||
|
||||
def _canceled_connecting_to_tor(self):
|
||||
self.common.log("TorConnectionWidget", "_canceled_connecting_to_tor")
|
||||
self.active = False
|
||||
self.onion.cleanup()
|
||||
|
||||
# Cancel connecting to Tor
|
||||
QtCore.QTimer.singleShot(1, self.cancel_clicked)
|
||||
|
||||
def _error_connecting_to_tor(self, msg):
|
||||
self.common.log("TorConnectionWidget", "_error_connecting_to_tor")
|
||||
self.active = False
|
||||
self.fail.emit(msg)
|
||||
|
||||
|
||||
class TorConnectionThread(QtCore.QThread):
|
||||
tor_status_update = QtCore.Signal(str, str)
|
||||
connected_to_tor = QtCore.Signal()
|
||||
canceled_connecting_to_tor = QtCore.Signal()
|
||||
error_connecting_to_tor = QtCore.Signal(str)
|
||||
|
||||
def __init__(self, common, settings, dialog):
|
||||
def __init__(self, common, settings, parent):
|
||||
super(TorConnectionThread, self).__init__()
|
||||
self.common = common
|
||||
self.common.log("TorConnectionThread", "__init__")
|
||||
self.settings = settings
|
||||
self.dialog = dialog
|
||||
self.parent = parent
|
||||
|
||||
def run(self):
|
||||
self.common.log("TorConnectionThread", "run")
|
||||
|
||||
# Connect to the Onion
|
||||
try:
|
||||
self.dialog.onion.connect(self.settings, False, self._tor_status_update)
|
||||
if self.dialog.onion.connected_to_tor:
|
||||
self.parent.onion.connect(self.settings, False, self._tor_status_update)
|
||||
if self.parent.onion.connected_to_tor:
|
||||
self.connected_to_tor.emit()
|
||||
else:
|
||||
self.canceled_connecting_to_tor.emit()
|
||||
@ -212,4 +321,4 @@ class TorConnectionThread(QtCore.QThread):
|
||||
self.tor_status_update.emit(progress, summary)
|
||||
|
||||
# Return False if the dialog was canceled
|
||||
return not self.dialog.wasCanceled()
|
||||
return not self.parent.wasCanceled()
|
@ -30,32 +30,30 @@ from onionshare_cli.onion import Onion
|
||||
|
||||
from . import strings
|
||||
from .widgets import Alert
|
||||
from .tor_connection_dialog import TorConnectionDialog
|
||||
from .tor_connection import TorConnectionWidget
|
||||
from .moat_dialog import MoatDialog
|
||||
from .gui_common import GuiCommon
|
||||
|
||||
|
||||
class TorSettingsDialog(QtWidgets.QDialog):
|
||||
class TorSettingsTab(QtWidgets.QWidget):
|
||||
"""
|
||||
Settings dialog.
|
||||
"""
|
||||
|
||||
settings_saved = QtCore.Signal()
|
||||
close_this_tab = QtCore.Signal()
|
||||
tor_is_connected = QtCore.Signal()
|
||||
tor_is_disconnected = QtCore.Signal()
|
||||
|
||||
def __init__(self, common):
|
||||
super(TorSettingsDialog, self).__init__()
|
||||
def __init__(self, common, tab_id, are_tabs_active, status_bar):
|
||||
super(TorSettingsTab, self).__init__()
|
||||
|
||||
self.common = common
|
||||
self.common.log("TorSettingsTab", "__init__")
|
||||
|
||||
self.common.log("TorSettingsDialog", "__init__")
|
||||
|
||||
self.status_bar = status_bar
|
||||
self.meek = Meek(common, get_tor_paths=self.common.gui.get_tor_paths)
|
||||
|
||||
self.setModal(True)
|
||||
self.setWindowTitle(strings._("gui_tor_settings_window_title"))
|
||||
self.setWindowIcon(QtGui.QIcon(GuiCommon.get_resource_path("images/logo.png")))
|
||||
|
||||
self.system = platform.system()
|
||||
self.tab_id = tab_id
|
||||
|
||||
# Connection type: either automatic, control port, or socket file
|
||||
|
||||
@ -299,6 +297,7 @@ class TorSettingsDialog(QtWidgets.QDialog):
|
||||
connection_type_radio_group_layout.addWidget(
|
||||
self.connection_type_socket_file_radio
|
||||
)
|
||||
connection_type_radio_group_layout.addStretch()
|
||||
connection_type_radio_group = QtWidgets.QGroupBox(
|
||||
strings._("gui_settings_connection_type_label")
|
||||
)
|
||||
@ -319,6 +318,28 @@ class TorSettingsDialog(QtWidgets.QDialog):
|
||||
connection_type_layout = QtWidgets.QVBoxLayout()
|
||||
connection_type_layout.addWidget(self.tor_settings_group)
|
||||
connection_type_layout.addWidget(self.connection_type_bridges_radio_group)
|
||||
connection_type_layout.addStretch()
|
||||
|
||||
# Settings are in columns
|
||||
columns_layout = QtWidgets.QHBoxLayout()
|
||||
columns_layout.addWidget(connection_type_radio_group)
|
||||
columns_layout.addSpacing(20)
|
||||
columns_layout.addLayout(connection_type_layout, stretch=1)
|
||||
columns_wrapper = QtWidgets.QWidget()
|
||||
columns_wrapper.setFixedHeight(400)
|
||||
columns_wrapper.setLayout(columns_layout)
|
||||
|
||||
# Tor connection widget
|
||||
self.tor_con = TorConnectionWidget(self.common, self.status_bar)
|
||||
self.tor_con.success.connect(self.tor_con_success)
|
||||
self.tor_con.fail.connect(self.tor_con_fail)
|
||||
self.tor_con.hide()
|
||||
self.tor_con_type = None
|
||||
|
||||
# Error label
|
||||
self.error_label = QtWidgets.QLabel()
|
||||
self.error_label.setStyleSheet(self.common.gui.css["tor_settings_error"])
|
||||
self.error_label.setWordWrap(True)
|
||||
|
||||
# Buttons
|
||||
self.test_tor_button = QtWidgets.QPushButton(
|
||||
@ -327,26 +348,42 @@ class TorSettingsDialog(QtWidgets.QDialog):
|
||||
self.test_tor_button.clicked.connect(self.test_tor_clicked)
|
||||
self.save_button = QtWidgets.QPushButton(strings._("gui_settings_button_save"))
|
||||
self.save_button.clicked.connect(self.save_clicked)
|
||||
self.cancel_button = QtWidgets.QPushButton(
|
||||
strings._("gui_settings_button_cancel")
|
||||
)
|
||||
self.cancel_button.clicked.connect(self.cancel_clicked)
|
||||
buttons_layout = QtWidgets.QHBoxLayout()
|
||||
buttons_layout.addWidget(self.error_label, stretch=1)
|
||||
buttons_layout.addSpacing(20)
|
||||
buttons_layout.addWidget(self.test_tor_button)
|
||||
buttons_layout.addStretch()
|
||||
buttons_layout.addWidget(self.save_button)
|
||||
buttons_layout.addWidget(self.cancel_button)
|
||||
|
||||
# Layout
|
||||
# Main layout
|
||||
main_layout = QtWidgets.QVBoxLayout()
|
||||
main_layout.addWidget(columns_wrapper)
|
||||
main_layout.addStretch()
|
||||
main_layout.addWidget(self.tor_con)
|
||||
main_layout.addStretch()
|
||||
main_layout.addLayout(buttons_layout)
|
||||
self.main_widget = QtWidgets.QWidget()
|
||||
self.main_widget.setLayout(main_layout)
|
||||
|
||||
# Tabs are active label
|
||||
active_tabs_label = QtWidgets.QLabel(
|
||||
strings._("gui_settings_stop_active_tabs_label")
|
||||
)
|
||||
active_tabs_label.setAlignment(QtCore.Qt.AlignHCenter)
|
||||
|
||||
# Active tabs layout
|
||||
active_tabs_layout = QtWidgets.QVBoxLayout()
|
||||
active_tabs_layout.addStretch()
|
||||
active_tabs_layout.addWidget(active_tabs_label)
|
||||
active_tabs_layout.addStretch()
|
||||
self.active_tabs_widget = QtWidgets.QWidget()
|
||||
self.active_tabs_widget.setLayout(active_tabs_layout)
|
||||
|
||||
layout = QtWidgets.QVBoxLayout()
|
||||
layout.addWidget(connection_type_radio_group)
|
||||
layout.addLayout(connection_type_layout)
|
||||
layout.addStretch()
|
||||
layout.addLayout(buttons_layout)
|
||||
|
||||
layout.addWidget(self.main_widget)
|
||||
layout.addWidget(self.active_tabs_widget)
|
||||
self.setLayout(layout)
|
||||
self.cancel_button.setFocus()
|
||||
|
||||
self.active_tabs_changed(are_tabs_active)
|
||||
self.reload_settings()
|
||||
|
||||
def reload_settings(self):
|
||||
@ -391,63 +428,68 @@ class TorSettingsDialog(QtWidgets.QDialog):
|
||||
self.old_settings.get("auth_password")
|
||||
)
|
||||
|
||||
if self.old_settings.get("no_bridges"):
|
||||
self.bridge_use_checkbox.setCheckState(QtCore.Qt.Unchecked)
|
||||
self.bridge_settings.hide()
|
||||
|
||||
else:
|
||||
if self.old_settings.get("bridges_enabled"):
|
||||
self.bridge_use_checkbox.setCheckState(QtCore.Qt.Checked)
|
||||
self.bridge_settings.show()
|
||||
|
||||
builtin_obfs4 = self.old_settings.get("tor_bridges_use_obfs4")
|
||||
builtin_meek_azure = self.old_settings.get(
|
||||
"tor_bridges_use_meek_lite_azure"
|
||||
)
|
||||
builtin_snowflake = self.old_settings.get("tor_bridges_use_snowflake")
|
||||
|
||||
if builtin_obfs4 or builtin_meek_azure or builtin_snowflake:
|
||||
bridges_type = self.old_settings.get("bridges_type")
|
||||
if bridges_type == "built-in":
|
||||
self.bridge_builtin_radio.setChecked(True)
|
||||
self.bridge_builtin_dropdown.show()
|
||||
if builtin_obfs4:
|
||||
self.bridge_moat_radio.setChecked(False)
|
||||
self.bridge_moat_textbox_options.hide()
|
||||
self.bridge_custom_radio.setChecked(False)
|
||||
self.bridge_custom_textbox_options.hide()
|
||||
|
||||
bridges_builtin_pt = self.old_settings.get("bridges_builtin_pt")
|
||||
if bridges_builtin_pt == "obfs4":
|
||||
self.bridge_builtin_dropdown.setCurrentText("obfs4")
|
||||
elif builtin_meek_azure:
|
||||
elif bridges_builtin_pt == "meek-azure":
|
||||
self.bridge_builtin_dropdown.setCurrentText("meek-azure")
|
||||
elif builtin_snowflake:
|
||||
else:
|
||||
self.bridge_builtin_dropdown.setCurrentText("snowflake")
|
||||
|
||||
self.bridge_moat_textbox_options.hide()
|
||||
self.bridge_custom_textbox_options.hide()
|
||||
|
||||
elif bridges_type == "moat":
|
||||
self.bridge_builtin_radio.setChecked(False)
|
||||
self.bridge_builtin_dropdown.hide()
|
||||
self.bridge_moat_radio.setChecked(True)
|
||||
self.bridge_moat_textbox_options.show()
|
||||
self.bridge_custom_radio.setChecked(False)
|
||||
self.bridge_custom_textbox_options.hide()
|
||||
|
||||
else:
|
||||
self.bridge_builtin_radio.setChecked(False)
|
||||
self.bridge_builtin_dropdown.hide()
|
||||
self.bridge_moat_radio.setChecked(False)
|
||||
self.bridge_moat_textbox_options.hide()
|
||||
self.bridge_custom_radio.setChecked(True)
|
||||
self.bridge_custom_textbox_options.show()
|
||||
|
||||
use_moat = self.old_settings.get("tor_bridges_use_moat")
|
||||
self.bridge_moat_radio.setChecked(use_moat)
|
||||
if use_moat:
|
||||
self.bridge_builtin_dropdown.hide()
|
||||
self.bridge_custom_textbox_options.hide()
|
||||
bridges_moat = self.old_settings.get("bridges_moat")
|
||||
self.bridge_moat_textbox.document().setPlainText(bridges_moat)
|
||||
bridges_custom = self.old_settings.get("bridges_custom")
|
||||
self.bridge_custom_textbox.document().setPlainText(bridges_custom)
|
||||
|
||||
moat_bridges = self.old_settings.get("tor_bridges_use_moat_bridges")
|
||||
self.bridge_moat_textbox.document().setPlainText(moat_bridges)
|
||||
if len(moat_bridges.strip()) > 0:
|
||||
self.bridge_moat_textbox_options.show()
|
||||
else:
|
||||
self.bridge_moat_textbox_options.hide()
|
||||
else:
|
||||
self.bridge_use_checkbox.setCheckState(QtCore.Qt.Unchecked)
|
||||
self.bridge_settings.hide()
|
||||
|
||||
custom_bridges = self.old_settings.get("tor_bridges_use_custom_bridges")
|
||||
if len(custom_bridges.strip()) != 0:
|
||||
self.bridge_custom_radio.setChecked(True)
|
||||
self.bridge_custom_textbox.setPlainText(custom_bridges)
|
||||
|
||||
self.bridge_builtin_dropdown.hide()
|
||||
self.bridge_moat_textbox_options.hide()
|
||||
self.bridge_custom_textbox_options.show()
|
||||
def active_tabs_changed(self, are_tabs_active):
|
||||
if are_tabs_active:
|
||||
self.main_widget.hide()
|
||||
self.active_tabs_widget.show()
|
||||
else:
|
||||
self.main_widget.show()
|
||||
self.active_tabs_widget.hide()
|
||||
|
||||
def connection_type_bundled_toggled(self, checked):
|
||||
"""
|
||||
Connection type bundled was toggled
|
||||
"""
|
||||
self.common.log("TorSettingsDialog", "connection_type_bundled_toggled")
|
||||
self.common.log("TorSettingsTab", "connection_type_bundled_toggled")
|
||||
if checked:
|
||||
self.tor_settings_group.hide()
|
||||
self.connection_type_socks.hide()
|
||||
@ -479,7 +521,7 @@ class TorSettingsDialog(QtWidgets.QDialog):
|
||||
"""
|
||||
if selection == "meek-azure":
|
||||
# Alert the user about meek's costliness if it looks like they're turning it on
|
||||
if not self.old_settings.get("tor_bridges_use_meek_lite_azure"):
|
||||
if not self.old_settings.get("bridges_builtin_pt") == "meek-azure":
|
||||
Alert(
|
||||
self.common,
|
||||
strings._("gui_settings_meek_lite_expensive_warning"),
|
||||
@ -499,7 +541,7 @@ class TorSettingsDialog(QtWidgets.QDialog):
|
||||
"""
|
||||
Request new bridge button clicked
|
||||
"""
|
||||
self.common.log("TorSettingsDialog", "bridge_moat_button_clicked")
|
||||
self.common.log("TorSettingsTab", "bridge_moat_button_clicked")
|
||||
|
||||
moat_dialog = MoatDialog(self.common, self.meek)
|
||||
moat_dialog.got_bridges.connect(self.bridge_moat_got_bridges)
|
||||
@ -509,7 +551,7 @@ class TorSettingsDialog(QtWidgets.QDialog):
|
||||
"""
|
||||
Got new bridges from moat
|
||||
"""
|
||||
self.common.log("TorSettingsDialog", "bridge_moat_got_bridges")
|
||||
self.common.log("TorSettingsTab", "bridge_moat_got_bridges")
|
||||
self.bridge_moat_textbox.document().setPlainText(bridges)
|
||||
self.bridge_moat_textbox.show()
|
||||
|
||||
@ -526,7 +568,7 @@ class TorSettingsDialog(QtWidgets.QDialog):
|
||||
"""
|
||||
Connection type automatic was toggled. If checked, hide authentication fields.
|
||||
"""
|
||||
self.common.log("TorSettingsDialog", "connection_type_automatic_toggled")
|
||||
self.common.log("TorSettingsTab", "connection_type_automatic_toggled")
|
||||
if checked:
|
||||
self.tor_settings_group.hide()
|
||||
self.connection_type_socks.hide()
|
||||
@ -537,7 +579,7 @@ class TorSettingsDialog(QtWidgets.QDialog):
|
||||
Connection type control port was toggled. If checked, show extra fields
|
||||
for Tor control address and port. If unchecked, hide those extra fields.
|
||||
"""
|
||||
self.common.log("TorSettingsDialog", "connection_type_control_port_toggled")
|
||||
self.common.log("TorSettingsTab", "connection_type_control_port_toggled")
|
||||
if checked:
|
||||
self.tor_settings_group.show()
|
||||
self.connection_type_control_port_extras.show()
|
||||
@ -551,7 +593,7 @@ class TorSettingsDialog(QtWidgets.QDialog):
|
||||
Connection type socket file was toggled. If checked, show extra fields
|
||||
for socket file. If unchecked, hide those extra fields.
|
||||
"""
|
||||
self.common.log("TorSettingsDialog", "connection_type_socket_file_toggled")
|
||||
self.common.log("TorSettingsTab", "connection_type_socket_file_toggled")
|
||||
if checked:
|
||||
self.tor_settings_group.show()
|
||||
self.connection_type_socket_file_extras.show()
|
||||
@ -564,7 +606,7 @@ class TorSettingsDialog(QtWidgets.QDialog):
|
||||
"""
|
||||
Authentication option no authentication was toggled.
|
||||
"""
|
||||
self.common.log("TorSettingsDialog", "authenticate_no_auth_toggled")
|
||||
self.common.log("TorSettingsTab", "authenticate_no_auth_toggled")
|
||||
if checked:
|
||||
self.authenticate_password_extras.hide()
|
||||
else:
|
||||
@ -575,39 +617,34 @@ class TorSettingsDialog(QtWidgets.QDialog):
|
||||
Test Tor Settings button clicked. With the given settings, see if we can
|
||||
successfully connect and authenticate to Tor.
|
||||
"""
|
||||
self.common.log("TorSettingsDialog", "test_tor_clicked")
|
||||
self.common.log("TorSettingsTab", "test_tor_clicked")
|
||||
|
||||
self.error_label.setText("")
|
||||
|
||||
settings = self.settings_from_fields()
|
||||
if not settings:
|
||||
return
|
||||
|
||||
onion = Onion(
|
||||
self.common, use_tmp_dir=True, get_tor_paths=self.common.gui.get_tor_paths
|
||||
self.test_tor_button.hide()
|
||||
self.save_button.hide()
|
||||
|
||||
self.test_onion = Onion(
|
||||
self.common,
|
||||
use_tmp_dir=True,
|
||||
get_tor_paths=self.common.gui.get_tor_paths,
|
||||
)
|
||||
|
||||
tor_con = TorConnectionDialog(self.common, settings, True, onion)
|
||||
tor_con.start()
|
||||
|
||||
# If Tor settings worked, show results
|
||||
if onion.connected_to_tor:
|
||||
Alert(
|
||||
self.common,
|
||||
strings._("settings_test_success").format(
|
||||
onion.tor_version,
|
||||
onion.supports_ephemeral,
|
||||
onion.supports_stealth,
|
||||
onion.supports_v3_onions,
|
||||
),
|
||||
title=strings._("gui_settings_connection_type_test_button"),
|
||||
)
|
||||
|
||||
# Clean up
|
||||
onion.cleanup()
|
||||
self.tor_con_type = "test"
|
||||
self.tor_con.show()
|
||||
self.tor_con.start(settings, True, self.test_onion)
|
||||
|
||||
def save_clicked(self):
|
||||
"""
|
||||
Save button clicked. Save current settings to disk.
|
||||
"""
|
||||
self.common.log("TorSettingsDialog", "save_clicked")
|
||||
self.common.log("TorSettingsTab", "save_clicked")
|
||||
|
||||
self.error_label.setText("")
|
||||
|
||||
def changed(s1, s2, keys):
|
||||
"""
|
||||
@ -630,7 +667,7 @@ class TorSettingsDialog(QtWidgets.QDialog):
|
||||
if not self.common.gui.local_only:
|
||||
if self.common.gui.onion.is_authenticated():
|
||||
self.common.log(
|
||||
"TorSettingsDialog", "save_clicked", "Connected to Tor"
|
||||
"TorSettingsTab", "save_clicked", "Connected to Tor"
|
||||
)
|
||||
|
||||
if changed(
|
||||
@ -645,10 +682,11 @@ class TorSettingsDialog(QtWidgets.QDialog):
|
||||
"socket_file_path",
|
||||
"auth_type",
|
||||
"auth_password",
|
||||
"no_bridges",
|
||||
"tor_bridges_use_obfs4",
|
||||
"tor_bridges_use_meek_lite_azure",
|
||||
"tor_bridges_use_custom_bridges",
|
||||
"bridges_enabled",
|
||||
"bridges_type",
|
||||
"bridges_builtin_pt",
|
||||
"bridges_moat",
|
||||
"bridges_custom",
|
||||
],
|
||||
):
|
||||
|
||||
@ -656,65 +694,86 @@ class TorSettingsDialog(QtWidgets.QDialog):
|
||||
|
||||
else:
|
||||
self.common.log(
|
||||
"TorSettingsDialog", "save_clicked", "Not connected to Tor"
|
||||
"TorSettingsTab", "save_clicked", "Not connected to Tor"
|
||||
)
|
||||
# Tor isn't connected, so try connecting
|
||||
reboot_onion = True
|
||||
|
||||
# Do we need to reinitialize Tor?
|
||||
if reboot_onion:
|
||||
# Tell the tabs that Tor is disconnected
|
||||
self.tor_is_disconnected.emit()
|
||||
|
||||
# Reinitialize the Onion object
|
||||
self.common.log(
|
||||
"TorSettingsDialog", "save_clicked", "rebooting the Onion"
|
||||
"TorSettingsTab", "save_clicked", "rebooting the Onion"
|
||||
)
|
||||
self.common.gui.onion.cleanup()
|
||||
|
||||
tor_con = TorConnectionDialog(self.common, settings)
|
||||
tor_con.start()
|
||||
|
||||
self.common.log(
|
||||
"TorSettingsDialog",
|
||||
"save_clicked",
|
||||
f"Onion done rebooting, connected to Tor: {self.common.gui.onion.connected_to_tor}",
|
||||
)
|
||||
|
||||
if (
|
||||
self.common.gui.onion.is_authenticated()
|
||||
and not tor_con.wasCanceled()
|
||||
):
|
||||
self.settings_saved.emit()
|
||||
self.close()
|
||||
self.test_tor_button.hide()
|
||||
self.save_button.hide()
|
||||
|
||||
self.tor_con_type = "save"
|
||||
self.tor_con.show()
|
||||
self.tor_con.start(settings)
|
||||
else:
|
||||
self.settings_saved.emit()
|
||||
self.close()
|
||||
self.close_this_tab.emit()
|
||||
else:
|
||||
self.settings_saved.emit()
|
||||
self.close()
|
||||
self.close_this_tab.emit()
|
||||
|
||||
def cancel_clicked(self):
|
||||
def tor_con_success(self):
|
||||
"""
|
||||
Cancel button clicked.
|
||||
Finished testing tor connection.
|
||||
"""
|
||||
self.common.log("TorSettingsDialog", "cancel_clicked")
|
||||
if (
|
||||
not self.common.gui.local_only
|
||||
and not self.common.gui.onion.is_authenticated()
|
||||
):
|
||||
self.tor_con.hide()
|
||||
self.test_tor_button.show()
|
||||
self.save_button.show()
|
||||
|
||||
if self.tor_con_type == "test":
|
||||
Alert(
|
||||
self.common,
|
||||
strings._("gui_tor_connection_canceled"),
|
||||
QtWidgets.QMessageBox.Warning,
|
||||
strings._("settings_test_success").format(
|
||||
self.test_onion.tor_version,
|
||||
self.test_onion.supports_ephemeral,
|
||||
self.test_onion.supports_stealth,
|
||||
self.test_onion.supports_v3_onions,
|
||||
),
|
||||
title=strings._("gui_settings_connection_type_test_button"),
|
||||
)
|
||||
sys.exit()
|
||||
else:
|
||||
self.close()
|
||||
self.test_onion.cleanup()
|
||||
|
||||
elif self.tor_con_type == "save":
|
||||
if (
|
||||
self.common.gui.onion.is_authenticated()
|
||||
and not self.tor_con.wasCanceled()
|
||||
):
|
||||
# Tell the tabs that Tor is connected
|
||||
self.tor_is_connected.emit()
|
||||
# Close the tab
|
||||
self.close_this_tab.emit()
|
||||
|
||||
self.tor_con_type = None
|
||||
|
||||
def tor_con_fail(self, msg):
|
||||
"""
|
||||
Finished testing tor connection.
|
||||
"""
|
||||
self.tor_con.hide()
|
||||
self.test_tor_button.show()
|
||||
self.save_button.show()
|
||||
|
||||
self.error_label.setText(msg)
|
||||
|
||||
if self.tor_con_type == "test":
|
||||
self.test_onion.cleanup()
|
||||
|
||||
self.tor_con_type = None
|
||||
|
||||
def settings_from_fields(self):
|
||||
"""
|
||||
Return a Settings object that's full of values from the settings dialog.
|
||||
"""
|
||||
self.common.log("TorSettingsDialog", "settings_from_fields")
|
||||
self.common.log("TorSettingsTab", "settings_from_fields")
|
||||
settings = Settings(self.common)
|
||||
settings.load() # To get the last update timestamp
|
||||
|
||||
@ -751,47 +810,30 @@ class TorSettingsDialog(QtWidgets.QDialog):
|
||||
|
||||
# Whether we use bridges
|
||||
if self.bridge_use_checkbox.checkState() == QtCore.Qt.Checked:
|
||||
settings.set("no_bridges", False)
|
||||
settings.set("bridges_enabled", True)
|
||||
|
||||
if self.bridge_builtin_radio.isChecked():
|
||||
selection = self.bridge_builtin_dropdown.currentText()
|
||||
if selection == "obfs4":
|
||||
settings.set("tor_bridges_use_obfs4", True)
|
||||
settings.set("tor_bridges_use_meek_lite_azure", False)
|
||||
settings.set("tor_bridges_use_snowflake", False)
|
||||
elif selection == "meek-azure":
|
||||
settings.set("tor_bridges_use_obfs4", False)
|
||||
settings.set("tor_bridges_use_meek_lite_azure", True)
|
||||
settings.set("tor_bridges_use_snowflake", False)
|
||||
elif selection == "snowflake":
|
||||
settings.set("tor_bridges_use_obfs4", False)
|
||||
settings.set("tor_bridges_use_meek_lite_azure", False)
|
||||
settings.set("tor_bridges_use_snowflake", True)
|
||||
settings.set("bridges_type", "built-in")
|
||||
|
||||
settings.set("tor_bridges_use_moat", False)
|
||||
settings.set("tor_bridges_use_custom_bridges", "")
|
||||
selection = self.bridge_builtin_dropdown.currentText()
|
||||
settings.set("bridges_builtin_pt", selection)
|
||||
|
||||
if self.bridge_moat_radio.isChecked():
|
||||
settings.set("tor_bridges_use_obfs4", False)
|
||||
settings.set("tor_bridges_use_meek_lite_azure", False)
|
||||
settings.set("tor_bridges_use_snowflake", False)
|
||||
|
||||
settings.set("tor_bridges_use_moat", True)
|
||||
|
||||
settings.set("bridges_type", "moat")
|
||||
moat_bridges = self.bridge_moat_textbox.toPlainText()
|
||||
if moat_bridges.strip() == "":
|
||||
Alert(self.common, strings._("gui_settings_moat_bridges_invalid"))
|
||||
if (
|
||||
self.connection_type_bundled_radio.isChecked()
|
||||
and moat_bridges.strip() == ""
|
||||
):
|
||||
self.error_label.setText(
|
||||
strings._("gui_settings_moat_bridges_invalid")
|
||||
)
|
||||
return False
|
||||
|
||||
settings.set("tor_bridges_use_moat_bridges", moat_bridges)
|
||||
|
||||
settings.set("tor_bridges_use_custom_bridges", "")
|
||||
settings.set("bridges_moat", moat_bridges)
|
||||
|
||||
if self.bridge_custom_radio.isChecked():
|
||||
settings.set("tor_bridges_use_obfs4", False)
|
||||
settings.set("tor_bridges_use_meek_lite_azure", False)
|
||||
settings.set("tor_bridges_use_snowflake", False)
|
||||
settings.set("tor_bridges_use_moat", False)
|
||||
settings.set("bridges_type", "custom")
|
||||
|
||||
new_bridges = []
|
||||
bridges = self.bridge_custom_textbox.toPlainText().split("\n")
|
||||
@ -822,26 +864,32 @@ class TorSettingsDialog(QtWidgets.QDialog):
|
||||
|
||||
if bridges_valid:
|
||||
new_bridges = "\n".join(new_bridges) + "\n"
|
||||
settings.set("tor_bridges_use_custom_bridges", new_bridges)
|
||||
settings.set("bridges_custom", new_bridges)
|
||||
else:
|
||||
Alert(self.common, strings._("gui_settings_tor_bridges_invalid"))
|
||||
self.error_label.setText(
|
||||
strings._("gui_settings_tor_bridges_invalid")
|
||||
)
|
||||
return False
|
||||
else:
|
||||
settings.set("no_bridges", True)
|
||||
settings.set("bridges_enabled", False)
|
||||
|
||||
return settings
|
||||
|
||||
def closeEvent(self, e):
|
||||
self.common.log("TorSettingsDialog", "closeEvent")
|
||||
self.common.log("TorSettingsTab", "closeEvent")
|
||||
|
||||
# On close, if Tor isn't connected, then quit OnionShare altogether
|
||||
if not self.common.gui.local_only:
|
||||
if not self.common.gui.onion.is_authenticated():
|
||||
self.common.log(
|
||||
"TorSettingsDialog",
|
||||
"TorSettingsTab",
|
||||
"closeEvent",
|
||||
"Closing while not connected to Tor",
|
||||
)
|
||||
|
||||
# Wait 1ms for the event loop to finish, then quit
|
||||
QtCore.QTimer.singleShot(1, self.common.gui.qtapp.quit)
|
||||
|
||||
def settings_have_changed(self):
|
||||
# Global settings have changed
|
||||
self.common.log("TorSettingsTab", "settings_have_changed")
|
Loading…
x
Reference in New Issue
Block a user