Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions electrum/gui/qt/network_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,18 +271,21 @@ def __init__(self, network: Network, config, wizard=False):
self.proxy_password.setPlaceholderText(_("Password"))
self.proxy_password.setEchoMode(QLineEdit.Password)
self.proxy_password.setFixedWidth(fixed_width_port)
self.proxy_isolate = QCheckBox(_("Use stream isolation"))

self.proxy_mode.currentIndexChanged.connect(self.set_proxy)
self.proxy_host.editingFinished.connect(self.set_proxy)
self.proxy_port.editingFinished.connect(self.set_proxy)
self.proxy_user.editingFinished.connect(self.set_proxy)
self.proxy_password.editingFinished.connect(self.set_proxy)
self.proxy_isolate.clicked.connect(self.set_proxy)

self.proxy_mode.currentIndexChanged.connect(self.proxy_settings_changed)
self.proxy_host.textEdited.connect(self.proxy_settings_changed)
self.proxy_port.textEdited.connect(self.proxy_settings_changed)
self.proxy_user.textEdited.connect(self.proxy_settings_changed)
self.proxy_password.textEdited.connect(self.proxy_settings_changed)
self.proxy_isolate.clicked.connect(self.proxy_settings_changed)

self.tor_cb = QCheckBox(_("Use Tor Proxy"))
self.tor_cb.setIcon(read_QIcon("tor_logo.png"))
Expand All @@ -297,6 +300,7 @@ def __init__(self, network: Network, config, wizard=False):
grid.addWidget(self.proxy_port, 4, 3)
grid.addWidget(self.proxy_user, 5, 2)
grid.addWidget(self.proxy_password, 5, 3)
grid.addWidget(self.proxy_isolate, 6, 2)
grid.setRowStretch(7, 1)

# Blockchain Tab
Expand Down Expand Up @@ -342,7 +346,7 @@ def __init__(self, network: Network, config, wizard=False):
def check_disable_proxy(self, b):
if not self.config.is_modifiable('proxy'):
b = False
for w in [self.proxy_mode, self.proxy_host, self.proxy_port, self.proxy_user, self.proxy_password]:
for w in [self.proxy_mode, self.proxy_host, self.proxy_port, self.proxy_user, self.proxy_password, self.proxy_isolate]:
w.setEnabled(b)

def enable_set_server(self):
Expand Down Expand Up @@ -407,6 +411,7 @@ def fill_in_proxy_settings(self):
self.proxy_port.setText(proxy_config.get("port"))
self.proxy_user.setText(proxy_config.get("user", ""))
self.proxy_password.setText(proxy_config.get("password", ""))
self.proxy_isolate.setChecked(proxy_config.get("isolate", True))

def layout(self):
return self.layout_
Expand Down Expand Up @@ -474,7 +479,8 @@ def set_proxy(self):
'host':str(self.proxy_host.text()),
'port':str(self.proxy_port.text()),
'user':str(self.proxy_user.text()),
'password':str(self.proxy_password.text())}
'password':str(self.proxy_password.text()),
'isolate':self.proxy_isolate.isChecked()}
else:
proxy = None
self.tor_cb.setChecked(False)
Expand Down Expand Up @@ -507,6 +513,7 @@ def use_tor_proxy(self, use_it):
self.proxy_port.setText(str(self.tor_proxy[1]))
self.proxy_user.setText("")
self.proxy_password.setText("")
self.proxy_isolate.setChecked(True)
self.tor_cb.setChecked(True)
self.proxy_cb.setChecked(True)
self.check_disable_proxy(use_it)
Expand Down
16 changes: 14 additions & 2 deletions electrum/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import sys
import traceback
import asyncio
import secrets
import socket
from typing import Tuple, Union, List, TYPE_CHECKING, Optional
from collections import defaultdict
Expand Down Expand Up @@ -62,6 +63,15 @@
BUCKET_NAME_OF_ONION_SERVERS = 'onion'


# Random authentication is useful when used with Tor for stream isolation.
class SOCKSRandomAuth(aiorpcx.socks.SOCKSUserAuth):
def __getitem__(self, key):
return secrets.token_hex(32)


SOCKSRandomAuth.__new__.__defaults__ = (None, None)


class NetworkTimeout:
# seconds
class Generic:
Expand Down Expand Up @@ -250,8 +260,10 @@ def diagnostic_name(self):

def _set_proxy(self, proxy: dict):
if proxy:
username, pw = proxy.get('user'), proxy.get('password')
if not username or not pw:
username, pw, isolate = proxy.get('user'), proxy.get('password'), proxy.get('isolate')
if isolate:
auth = SOCKSRandomAuth()
elif not username or not pw:
auth = None
else:
auth = aiorpcx.socks.SOCKSUserAuth(username, pw)
Expand Down
14 changes: 13 additions & 1 deletion electrum/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,8 @@ def serialize_proxy(p):
if not isinstance(p, dict):
return None
return ':'.join([p.get('mode'), p.get('host'), p.get('port'),
p.get('user', ''), p.get('password', '')])
p.get('user', ''), p.get('password', ''),
('1' if p.get('isolate', True) else '0')])


def deserialize_proxy(s: str) -> Optional[dict]:
Expand Down Expand Up @@ -177,6 +178,17 @@ def deserialize_proxy(s: str) -> Optional[dict]:
n += 1
if len(args) > n:
proxy["password"] = args[n]
n += 1
if len(args) > n:
isolate = args[n]
if isolate == "0":
proxy["isolate"] = False
elif isolate == "1":
proxy["isolate"] = True
else:
raise Exception("Couldn't parse proxy isolation setting: " + isolate)
else:
proxy["isolate"] = True
return proxy


Expand Down