tMerge pull request #2193 from bauerj/socks-auth - electrum - Electrum Bitcoin wallet
 (HTM) git clone https://git.parazyd.org/electrum
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Submodules
       ---
 (DIR) commit bc31d83466ce649675605a8946a3bb26ab909aeb
 (DIR) parent 622e50163830f7e76e668ea4f54b3b910bb055c8
 (HTM) Author: ThomasV <thomasv@electrum.org>
       Date:   Sat, 25 Feb 2017 15:05:57 +0100
       
       Merge pull request #2193 from bauerj/socks-auth
       
       Allow using a SOCKS5 proxy with authentication
       Diffstat:
         M gui/qt/network_dialog.py            |      30 +++++++++++++++++++++---------
         M lib/network.py                      |      15 +++++++++++++--
       
       2 files changed, 34 insertions(+), 11 deletions(-)
       ---
 (DIR) diff --git a/gui/qt/network_dialog.py b/gui/qt/network_dialog.py
       t@@ -155,15 +155,17 @@ class NetworkChoiceLayout(object):
                self.proxy_port = QLineEdit()
                self.proxy_port.setFixedWidth(60)
                self.proxy_mode.addItems(['NONE', 'SOCKS4', 'SOCKS5', 'HTTP'])
       +        self.proxy_user = QLineEdit()
       +        self.proxy_user.setPlaceholderText(_("Proxy user"))
       +        self.proxy_password = QLineEdit()
       +        self.proxy_password.setPlaceholderText(_("Password"))
       +        self.proxy_password.setEchoMode(QLineEdit.Password)
       +        self.proxy_password.setFixedWidth(60)
        
                def check_for_disable(index = False):
                    if self.config.is_modifiable('proxy'):
       -                if self.proxy_mode.currentText() != 'NONE':
       -                    self.proxy_host.setEnabled(True)
       -                    self.proxy_port.setEnabled(True)
       -                else:
       -                    self.proxy_host.setEnabled(False)
       -                    self.proxy_port.setEnabled(False)
       +                for w in [self.proxy_host, self.proxy_port, self.proxy_user, self.proxy_password]:
       +                    w.setEnabled(self.proxy_mode.currentText() != 'NONE')
                    else:
                        for w in [self.proxy_host, self.proxy_port, self.proxy_mode]: w.setEnabled(False)
        
       t@@ -173,20 +175,26 @@ class NetworkChoiceLayout(object):
                self.proxy_mode.setCurrentIndex(self.proxy_mode.findText(str(proxy_config.get("mode").upper())))
                self.proxy_host.setText(proxy_config.get("host"))
                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_mode.connect(self.proxy_mode, SIGNAL('currentIndexChanged(int)'), self.proxy_settings_changed)
                self.proxy_host.connect(self.proxy_host, SIGNAL('textEdited(QString)'), self.proxy_settings_changed)
                self.proxy_port.connect(self.proxy_port, SIGNAL('textEdited(QString)'), self.proxy_settings_changed)
       +        self.proxy_user.connect(self.proxy_user, SIGNAL('textEdited(QString)'), self.proxy_settings_changed)
       +        self.proxy_password.connect(self.proxy_password, SIGNAL('textEdited(QString)'), self.proxy_settings_changed)
        
                grid.addWidget(QLabel(_('Proxy') + ':'), 4, 0)
                grid.addWidget(self.proxy_mode, 4, 1)
                grid.addWidget(self.proxy_host, 4, 2)
                grid.addWidget(self.proxy_port, 4, 3)
       -        self.tor_button = QCheckBox("Use Tor Proxy")
       +        grid.addWidget(self.proxy_user, 5, 2)
       +        grid.addWidget(self.proxy_password, 5, 3)
       +        self.tor_button = QCheckBox(_("Use Tor Proxy"))
                self.tor_button.setIcon(QIcon(":icons/tor_logo.png"))
                self.tor_button.hide()
                self.tor_button.clicked.connect(self.use_tor_proxy)
       -        grid.addWidget(self.tor_button, 5, 1, 1, 2)
       +        grid.addWidget(self.tor_button, 6, 2, 1, 2)
                self.layout_ = vbox
                self.td = td = TorDetector()
                td.found_proxy.connect(self.suggest_proxy)
       t@@ -258,7 +266,9 @@ class NetworkChoiceLayout(object):
                if self.proxy_mode.currentText() != 'NONE':
                    proxy = { 'mode':str(self.proxy_mode.currentText()).lower(),
                              'host':str(self.proxy_host.text()),
       -                      'port':str(self.proxy_port.text()) }
       +                      'port':str(self.proxy_port.text()),
       +                      'user':str(self.proxy_user.text()),
       +                      'password':str(self.proxy_password.text())}
                else:
                    proxy = None
        
       t@@ -284,6 +294,8 @@ class NetworkChoiceLayout(object):
                    self.proxy_mode.setCurrentIndex(2)
                    self.proxy_host.setText("127.0.0.1")
                    self.proxy_port.setText(str(self.tor_proxy[1]))
       +            self.proxy_user.setText("")
       +            self.proxy_password.setText("")
                    self.tor_button.setChecked(True)
        
            def proxy_settings_changed(self):
 (DIR) diff --git a/lib/network.py b/lib/network.py
       t@@ -129,7 +129,7 @@ proxy_modes = ['socks4', 'socks5', 'http']
        def serialize_proxy(p):
            if type(p) != dict:
                return None
       -    return ':'.join([p.get('mode'),p.get('host'), p.get('port')])
       +    return ':'.join([p.get('mode'),p.get('host'), p.get('port'), p.get('user'), p.get('password')])
        
        def deserialize_proxy(s):
            if type(s) not in [str, unicode]:
       t@@ -147,8 +147,14 @@ def deserialize_proxy(s):
                n += 1
            if len(args) > n:
                proxy["port"] = args[n]
       +        n += 1
            else:
                proxy["port"] = "8080" if proxy["mode"] == "http" else "1080"
       +    if len(args) > n:
       +        proxy["user"] = args[n]
       +        n += 1
       +    if len(args) > n:
       +        proxy["password"] = args[n]
            return proxy
        
        def deserialize_server(server_str):
       t@@ -400,7 +406,12 @@ class Network(util.DaemonThread):
                if proxy:
                    self.print_error('setting proxy', proxy)
                    proxy_mode = proxy_modes.index(proxy["mode"]) + 1
       -            socks.setdefaultproxy(proxy_mode, proxy["host"], int(proxy["port"]))
       +            socks.setdefaultproxy(proxy_mode,
       +                                  proxy["host"],
       +                                  int(proxy["port"]),
       +                                  # socks.py seems to want either None or a non-empty string
       +                                  username=(proxy.get("user", "") or None),
       +                                  password=(proxy.get("password", "") or None))
                    socket.socket = socks.socksocket
                    # prevent dns leaks, see http://stackoverflow.com/questions/13184205/dns-over-proxy
                    socket.getaddrinfo = lambda *args: [(socket.AF_INET, socket.SOCK_STREAM, 6, '', (args[0], args[1]))]