mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-09-04 21:05:11 +00:00
Fixed merged conflict and added folder creation on first load
This commit is contained in:
commit
23ffbc3e48
9 changed files with 502 additions and 26 deletions
9
electrum
9
electrum
|
@ -37,9 +37,9 @@ except ImportError:
|
|||
sys.exit("Error: AES does not seem to be installed. Try 'sudo pip install slowaes'")
|
||||
|
||||
try:
|
||||
from lib import Wallet, WalletSynchronizer, format_satoshis, mnemonic, prompt_password, SimpleConfig
|
||||
from lib import Wallet, WalletSynchronizer, format_satoshis, mnemonic, prompt_password, parse_proxy_options, SimpleConfig
|
||||
except ImportError:
|
||||
from electrum import Wallet, WalletSynchronizer, format_satoshis, mnemonic, prompt_password, SimpleConfig
|
||||
from electrum import Wallet, WalletSynchronizer, format_satoshis, mnemonic, prompt_password, parse_proxy_options, SimpleConfig
|
||||
|
||||
from decimal import Decimal
|
||||
|
||||
|
@ -116,8 +116,11 @@ if __name__ == '__main__':
|
|||
parser.add_option("-s", "--fromaddr", dest="from_addr", default=None, help="set source address for payto/mktx. if it isn't in the wallet, it will ask for the private key unless supplied in the format public_key:private_key. It's not saved in the wallet.")
|
||||
parser.add_option("-c", "--changeaddr", dest="change_addr", default=None, help="set the change address for payto/mktx. default is a spare address, or the source address if it's not in the wallet")
|
||||
parser.add_option("-r", "--remote", dest="remote_url", default=None, help="URL of a remote wallet")
|
||||
parser.add_option("-p", "--proxy", dest="proxy", default=simple_config.config["proxy"], help="set proxy [type:]host[:port], where type is socks4,socks5 or http")
|
||||
options, args = parser.parse_args()
|
||||
|
||||
if type(options.proxy) == type(''):
|
||||
options.proxy = parse_proxy_options(options.proxy)
|
||||
|
||||
wallet = Wallet()
|
||||
wallet.set_path(options.wallet_path)
|
||||
|
@ -179,7 +182,7 @@ if __name__ == '__main__':
|
|||
sys.exit("Error: Unknown GUI: " + options.gui)
|
||||
|
||||
gui = gui.ElectrumGui(wallet)
|
||||
interface = WalletSynchronizer(wallet, True, gui.server_list_changed)
|
||||
interface = WalletSynchronizer(wallet, True, gui.server_list_changed, options.proxy)
|
||||
interface.start()
|
||||
|
||||
try:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from wallet import Wallet, format_satoshis, prompt_password
|
||||
from interface import WalletSynchronizer
|
||||
from interface import WalletSynchronizer, parse_proxy_options
|
||||
from interface import TcpStratumInterface
|
||||
from simple_config import SimpleConfig
|
||||
|
|
|
@ -5,6 +5,7 @@ from PyQt4.QtGui import *
|
|||
|
||||
from decimal import Decimal as D
|
||||
from interface import DEFAULT_SERVERS
|
||||
from simple_config import SimpleConfig
|
||||
from util import get_resource_path as rsrc
|
||||
from i18n import _
|
||||
import decimal
|
||||
|
@ -231,6 +232,12 @@ class MiniWindow(QDialog):
|
|||
close_shortcut = QShortcut(QKeySequence("Ctrl+W"), self)
|
||||
close_shortcut.activated.connect(self.close)
|
||||
|
||||
cfg = SimpleConfig()
|
||||
g = cfg.config["winpos-lite"]
|
||||
self.setGeometry(g[0], g[1], g[2], g[3])
|
||||
show_history.setChecked(cfg.config["history"])
|
||||
self.show_history(cfg.config["history"])
|
||||
|
||||
self.setWindowIcon(QIcon(":electrum.png"))
|
||||
self.setWindowTitle("Electrum")
|
||||
self.setWindowFlags(Qt.Window|Qt.MSWindowsFixedSizeDialogHint)
|
||||
|
@ -247,6 +254,12 @@ class MiniWindow(QDialog):
|
|||
QDir.setCurrent(old_path)
|
||||
|
||||
def closeEvent(self, event):
|
||||
cfg = SimpleConfig()
|
||||
g = self.geometry()
|
||||
cfg.set_key("winpos-lite", [g.left(),g.top(),g.width(),g.height()])
|
||||
cfg.set_key("history", self.history_list.isVisible())
|
||||
cfg.save_config()
|
||||
|
||||
super(MiniWindow, self).closeEvent(event)
|
||||
qApp.quit()
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ except:
|
|||
sys.exit("Error: Could not import icons_rc.py, please generate it with: 'pyrcc4 icons.qrc -o lib/icons_rc.py'")
|
||||
|
||||
from wallet import format_satoshis
|
||||
from simple_config import SimpleConfig
|
||||
import bmp, mnemonic, pyqrnative, qrscanner
|
||||
from simple_config import SimpleConfig
|
||||
|
||||
|
@ -203,7 +204,9 @@ class ElectrumWindow(QMainWindow):
|
|||
tabs.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
||||
self.setCentralWidget(tabs)
|
||||
self.create_status_bar()
|
||||
self.setGeometry(100,100,840,400)
|
||||
cfg = SimpleConfig()
|
||||
g = cfg.config["winpos-qt"]
|
||||
self.setGeometry(g[0], g[1], g[2], g[3])
|
||||
title = 'Electrum ' + self.wallet.electrum_version + ' - ' + self.wallet.path
|
||||
if not self.wallet.seed: title += ' [seedless]'
|
||||
self.setWindowTitle( title )
|
||||
|
@ -1392,6 +1395,24 @@ class ElectrumWindow(QMainWindow):
|
|||
hbox.addWidget(radio2)
|
||||
|
||||
vbox.addLayout(hbox)
|
||||
|
||||
hbox = QHBoxLayout()
|
||||
proxy_mode = QComboBox()
|
||||
proxy_host = QLineEdit()
|
||||
proxy_host.setFixedWidth(200)
|
||||
proxy_port = QLineEdit()
|
||||
proxy_port.setFixedWidth(50)
|
||||
proxy_mode.addItems(['NONE', 'SOCKS4', 'SOCKS5', 'HTTP'])
|
||||
proxy_mode.setCurrentIndex(proxy_mode.findText(str(interface.proxy["mode"]).upper()))
|
||||
proxy_host.setText(interface.proxy["host"])
|
||||
proxy_port.setText(interface.proxy["port"])
|
||||
hbox.addWidget(QLabel(_('Proxy') + ':'))
|
||||
hbox.addWidget(proxy_mode)
|
||||
hbox.addWidget(proxy_host)
|
||||
hbox.addWidget(proxy_port)
|
||||
vbox.addLayout(hbox)
|
||||
|
||||
hbox = QHBoxLayout()
|
||||
|
||||
if wallet.interface.servers:
|
||||
label = _('Active Servers')
|
||||
|
@ -1425,9 +1446,12 @@ class ElectrumWindow(QMainWindow):
|
|||
server = unicode( host_line.text() )
|
||||
|
||||
try:
|
||||
wallet.set_server(server)
|
||||
except:
|
||||
QMessageBox.information(None, _('Error'), 'error', _('OK'))
|
||||
cfg = SimpleConfig()
|
||||
cfg.set_key("proxy", { u'mode':unicode(proxy_mode.currentText()).lower(), u'host':unicode(proxy_host.text()), u'port':unicode(proxy_port.text()) })
|
||||
cfg.save_config()
|
||||
wallet.set_server(server, cfg.config["proxy"])
|
||||
except Exception as err:
|
||||
QMessageBox.information(None, _('Error'), str(err), _('OK'))
|
||||
if parent == None:
|
||||
sys.exit(1)
|
||||
else:
|
||||
|
@ -1435,6 +1459,12 @@ class ElectrumWindow(QMainWindow):
|
|||
|
||||
return True
|
||||
|
||||
def closeEvent(self, event):
|
||||
cfg = SimpleConfig()
|
||||
g = self.geometry()
|
||||
cfg.set_key("winpos-qt", [g.left(),g.top(),g.width(),g.height()])
|
||||
cfg.save_config()
|
||||
event.accept()
|
||||
|
||||
|
||||
class ElectrumGui:
|
||||
|
|
|
@ -28,6 +28,7 @@ DEFAULT_SERVERS = [ 'ecdsa.org:50001:t',
|
|||
'electrum.novit.ro:50001:t',
|
||||
'electrum.bytesized-hosting.com:50001:t'] # list of default servers
|
||||
|
||||
proxy_modes = ['none', 'socks4', 'socks5', 'http' ]
|
||||
|
||||
def replace_keys(obj, old_key, new_key):
|
||||
if isinstance(obj, dict):
|
||||
|
@ -47,13 +48,29 @@ def old_to_new(d):
|
|||
replace_keys(d, 'is_in', 'is_input')
|
||||
replace_keys(d, 'raw_scriptPubKey', 'raw_output_script')
|
||||
|
||||
def parse_proxy_options(s):
|
||||
proxy = { "mode":"socks5", "host":"localhost" }
|
||||
args = s.split(':')
|
||||
n = 0
|
||||
if proxy_modes.count(args[n]) == 1:
|
||||
proxy["mode"] = args[n]
|
||||
n += 1
|
||||
if len(args) > n:
|
||||
proxy["host"] = args[n]
|
||||
n += 1
|
||||
if len(args) > n:
|
||||
proxy["port"] = args[n]
|
||||
else:
|
||||
proxy["port"] = "8080" if proxy["mode"] == "http" else "1080"
|
||||
return proxy
|
||||
|
||||
class Interface(threading.Thread):
|
||||
def __init__(self, host, port, debug_server):
|
||||
def __init__(self, host, port, debug_server, proxy):
|
||||
threading.Thread.__init__(self)
|
||||
self.daemon = True
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.proxy = proxy
|
||||
|
||||
self.servers = [] # actual list from IRC
|
||||
self.rtime = 0
|
||||
|
@ -121,8 +138,8 @@ class Interface(threading.Thread):
|
|||
class PollingInterface(Interface):
|
||||
""" non-persistent connection. synchronous calls"""
|
||||
|
||||
def __init__(self, host, port, debug_server):
|
||||
Interface.__init__(self, host, port, debug_server)
|
||||
def __init__(self, host, port, debug_server, proxy):
|
||||
Interface.__init__(self, host, port, debug_server, proxy)
|
||||
self.session_id = None
|
||||
self.debug_server = debug_server
|
||||
|
||||
|
@ -173,7 +190,11 @@ class HttpStratumInterface(PollingInterface):
|
|||
|
||||
def send(self, messages):
|
||||
import urllib2, json, time, cookielib
|
||||
|
||||
|
||||
if self.proxy["mode"] != "none":
|
||||
import socks
|
||||
socks.setdefaultproxy(proxy_modes.index(self.proxy["mode"]), self.proxy["host"], int(self.proxy["port"]) )
|
||||
socks.wrapmodule(urllib2)
|
||||
cj = cookielib.CookieJar()
|
||||
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
|
||||
urllib2.install_opener(opener)
|
||||
|
@ -232,16 +253,23 @@ class HttpStratumInterface(PollingInterface):
|
|||
class TcpStratumInterface(Interface):
|
||||
"""json-rpc over persistent TCP connection, asynchronous"""
|
||||
|
||||
def __init__(self, host, port, debug_server):
|
||||
Interface.__init__(self, host, port, debug_server)
|
||||
def __init__(self, host, port, debug_server, proxy):
|
||||
Interface.__init__(self, host, port, debug_server, proxy)
|
||||
self.debug_server = debug_server
|
||||
|
||||
def init_socket(self):
|
||||
self.s = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
|
||||
global proxy_modes
|
||||
if self.proxy["mode"] == "none":
|
||||
self.s = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
|
||||
else:
|
||||
import socks
|
||||
self.s = socks.socksocket()
|
||||
print "Using Proxy", self.proxy
|
||||
self.s.setproxy(proxy_modes.index(self.proxy["mode"]), self.proxy["host"], int(self.proxy["port"]) )
|
||||
self.s.settimeout(60)
|
||||
self.s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
|
||||
try:
|
||||
self.s.connect(( self.host, self.port))
|
||||
self.s.connect(( self.host.encode('ascii'), int(self.port)))
|
||||
self.is_connected = True
|
||||
self.send([('server.version', [ELECTRUM_VERSION])])
|
||||
print "Connected to %s:%d"%(self.host,self.port)
|
||||
|
@ -305,11 +333,12 @@ class TcpStratumInterface(Interface):
|
|||
|
||||
class WalletSynchronizer(threading.Thread):
|
||||
|
||||
def __init__(self, wallet, loop=False, servers_loaded_callback=None):
|
||||
def __init__(self, wallet, loop=False, servers_loaded_callback=None, proxy=None):
|
||||
threading.Thread.__init__(self)
|
||||
self.daemon = True
|
||||
self.wallet = wallet
|
||||
self.loop = loop
|
||||
self.proxy = proxy
|
||||
self.init_interface()
|
||||
self.servers_loaded_callback = servers_loaded_callback
|
||||
|
||||
|
@ -331,7 +360,7 @@ class WalletSynchronizer(threading.Thread):
|
|||
print_error("Error: Unknown protocol")
|
||||
InterfaceClass = TcpStratumInterface
|
||||
|
||||
self.interface = InterfaceClass(host, port, self.wallet.debug_server)
|
||||
self.interface = InterfaceClass(host, port, self.wallet.debug_server, self.proxy)
|
||||
self.wallet.interface = self.interface
|
||||
|
||||
def handle_response(self, r):
|
||||
|
@ -429,6 +458,7 @@ class WalletSynchronizer(threading.Thread):
|
|||
if self.loop:
|
||||
time.sleep(5)
|
||||
# Server has been changed. Copy callback for new interface.
|
||||
self.proxy = self.interface.proxy
|
||||
self.init_interface()
|
||||
self.start_interface()
|
||||
continue
|
||||
|
|
|
@ -4,7 +4,9 @@ from util import user_dir
|
|||
|
||||
class SimpleConfig:
|
||||
|
||||
default_options = {"gui": "lite"}
|
||||
|
||||
default_options = {"gui": "lite", "proxy": { "mode": "none", "host":"localhost", "port":"8080" },
|
||||
"winpos-qt": [100, 100, 840, 400], "winpos-lite": [4, 25, 351, 149], "history": False }
|
||||
|
||||
def __init__(self):
|
||||
# Find electrum data folder
|
||||
|
@ -18,25 +20,39 @@ class SimpleConfig:
|
|||
if not os.path.exists(self.config_folder):
|
||||
os.mkdir(self.config_folder)
|
||||
self.save_config()
|
||||
|
||||
|
||||
def set_key(self, key, value, save = True):
|
||||
self.config[key] = value
|
||||
if save == True:
|
||||
self.save_config()
|
||||
|
||||
|
||||
def save_config(self):
|
||||
if not os.path.exists(self.config_folder):
|
||||
os.mkdir(self.config_folder)
|
||||
f = open(self.config_file_path(), "w+")
|
||||
f.write(json.dumps(self.config))
|
||||
|
||||
|
||||
def load_config(self):
|
||||
f = open(self.config_file_path(), "r")
|
||||
file_contents = f.read()
|
||||
if file_contents:
|
||||
self.config = json.loads(file_contents)
|
||||
user_config = json.loads(file_contents)
|
||||
for i in user_config:
|
||||
self.config[i] = user_config[i]
|
||||
else:
|
||||
self.config = self.default_options
|
||||
self.save_config()
|
||||
|
||||
|
||||
def config_file_path(self):
|
||||
return "%s" % (self.config_folder + "/config.json")
|
||||
|
||||
def __init__(self):
|
||||
# Find electrum data folder
|
||||
self.config_folder = user_dir()
|
||||
self.config = self.default_options
|
||||
# Read the file
|
||||
if os.path.exists(self.config_file_path()):
|
||||
self.load_config()
|
||||
self.save_config()
|
||||
|
||||
|
||||
|
|
382
lib/socks.py
Normal file
382
lib/socks.py
Normal file
|
@ -0,0 +1,382 @@
|
|||
"""SocksiPy - Python SOCKS module.
|
||||
Version 1.00
|
||||
|
||||
Copyright 2006 Dan-Haim. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
3. Neither the name of Dan Haim nor the names of his contributors may be used
|
||||
to endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY DAN HAIM "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
EVENT SHALL DAN HAIM OR HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMANGE.
|
||||
|
||||
|
||||
This module provides a standard socket-like interface for Python
|
||||
for tunneling connections through SOCKS proxies.
|
||||
|
||||
"""
|
||||
|
||||
"""
|
||||
|
||||
Minor modifications made by Christopher Gilbert (http://motomastyle.com/)
|
||||
for use in PyLoris (http://pyloris.sourceforge.net/)
|
||||
|
||||
Minor modifications made by Mario Vilas (http://breakingcode.wordpress.com/)
|
||||
mainly to merge bug fixes found in Sourceforge
|
||||
|
||||
"""
|
||||
|
||||
import socket
|
||||
import struct
|
||||
import sys
|
||||
|
||||
PROXY_TYPE_SOCKS4 = 1
|
||||
PROXY_TYPE_SOCKS5 = 2
|
||||
PROXY_TYPE_HTTP = 3
|
||||
|
||||
_defaultproxy = None
|
||||
_orgsocket = socket.socket
|
||||
|
||||
class ProxyError(Exception): pass
|
||||
class GeneralProxyError(ProxyError): pass
|
||||
class Socks5AuthError(ProxyError): pass
|
||||
class Socks5Error(ProxyError): pass
|
||||
class Socks4Error(ProxyError): pass
|
||||
class HTTPError(ProxyError): pass
|
||||
|
||||
_generalerrors = ("success",
|
||||
"invalid data",
|
||||
"not connected",
|
||||
"not available",
|
||||
"bad proxy type",
|
||||
"bad input")
|
||||
|
||||
_socks5errors = ("succeeded",
|
||||
"general SOCKS server failure",
|
||||
"connection not allowed by ruleset",
|
||||
"Network unreachable",
|
||||
"Host unreachable",
|
||||
"Connection refused",
|
||||
"TTL expired",
|
||||
"Command not supported",
|
||||
"Address type not supported",
|
||||
"Unknown error")
|
||||
|
||||
_socks5autherrors = ("succeeded",
|
||||
"authentication is required",
|
||||
"all offered authentication methods were rejected",
|
||||
"unknown username or invalid password",
|
||||
"unknown error")
|
||||
|
||||
_socks4errors = ("request granted",
|
||||
"request rejected or failed",
|
||||
"request rejected because SOCKS server cannot connect to identd on the client",
|
||||
"request rejected because the client program and identd report different user-ids",
|
||||
"unknown error")
|
||||
|
||||
def setdefaultproxy(proxytype=None, addr=None, port=None, rdns=True, username=None, password=None):
|
||||
"""setdefaultproxy(proxytype, addr[, port[, rdns[, username[, password]]]])
|
||||
Sets a default proxy which all further socksocket objects will use,
|
||||
unless explicitly changed.
|
||||
"""
|
||||
global _defaultproxy
|
||||
_defaultproxy = (proxytype, addr, port, rdns, username, password)
|
||||
|
||||
def wrapmodule(module):
|
||||
"""wrapmodule(module)
|
||||
Attempts to replace a module's socket library with a SOCKS socket. Must set
|
||||
a default proxy using setdefaultproxy(...) first.
|
||||
This will only work on modules that import socket directly into the namespace;
|
||||
most of the Python Standard Library falls into this category.
|
||||
"""
|
||||
if _defaultproxy != None:
|
||||
module.socket.socket = socksocket
|
||||
else:
|
||||
raise GeneralProxyError((4, "no proxy specified"))
|
||||
|
||||
class socksocket(socket.socket):
|
||||
"""socksocket([family[, type[, proto]]]) -> socket object
|
||||
Open a SOCKS enabled socket. The parameters are the same as
|
||||
those of the standard socket init. In order for SOCKS to work,
|
||||
you must specify family=AF_INET, type=SOCK_STREAM and proto=0.
|
||||
"""
|
||||
|
||||
def __init__(self, family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0, _sock=None):
|
||||
_orgsocket.__init__(self, family, type, proto, _sock)
|
||||
if _defaultproxy != None:
|
||||
self.__proxy = _defaultproxy
|
||||
else:
|
||||
self.__proxy = (None, None, None, None, None, None)
|
||||
self.__proxysockname = None
|
||||
self.__proxypeername = None
|
||||
|
||||
def __recvall(self, count):
|
||||
"""__recvall(count) -> data
|
||||
Receive EXACTLY the number of bytes requested from the socket.
|
||||
Blocks until the required number of bytes have been received.
|
||||
"""
|
||||
data = self.recv(count)
|
||||
while len(data) < count:
|
||||
d = self.recv(count-len(data))
|
||||
if not d: raise GeneralProxyError((0, "connection closed unexpectedly"))
|
||||
data = data + d
|
||||
return data
|
||||
|
||||
def setproxy(self, proxytype=None, addr=None, port=None, rdns=True, username=None, password=None):
|
||||
"""setproxy(proxytype, addr[, port[, rdns[, username[, password]]]])
|
||||
Sets the proxy to be used.
|
||||
proxytype - The type of the proxy to be used. Three types
|
||||
are supported: PROXY_TYPE_SOCKS4 (including socks4a),
|
||||
PROXY_TYPE_SOCKS5 and PROXY_TYPE_HTTP
|
||||
addr - The address of the server (IP or DNS).
|
||||
port - The port of the server. Defaults to 1080 for SOCKS
|
||||
servers and 8080 for HTTP proxy servers.
|
||||
rdns - Should DNS queries be preformed on the remote side
|
||||
(rather than the local side). The default is True.
|
||||
Note: This has no effect with SOCKS4 servers.
|
||||
username - Username to authenticate with to the server.
|
||||
The default is no authentication.
|
||||
password - Password to authenticate with to the server.
|
||||
Only relevant when username is also provided.
|
||||
"""
|
||||
self.__proxy = (proxytype, addr, port, rdns, username, password)
|
||||
|
||||
def __negotiatesocks5(self, destaddr, destport):
|
||||
"""__negotiatesocks5(self,destaddr,destport)
|
||||
Negotiates a connection through a SOCKS5 server.
|
||||
"""
|
||||
# First we'll send the authentication packages we support.
|
||||
if (self.__proxy[4]!=None) and (self.__proxy[5]!=None):
|
||||
# The username/password details were supplied to the
|
||||
# setproxy method so we support the USERNAME/PASSWORD
|
||||
# authentication (in addition to the standard none).
|
||||
self.sendall(struct.pack('BBBB', 0x05, 0x02, 0x00, 0x02))
|
||||
else:
|
||||
# No username/password were entered, therefore we
|
||||
# only support connections with no authentication.
|
||||
self.sendall(struct.pack('BBB', 0x05, 0x01, 0x00))
|
||||
# We'll receive the server's response to determine which
|
||||
# method was selected
|
||||
chosenauth = self.__recvall(2)
|
||||
if chosenauth[0:1] != chr(0x05).encode():
|
||||
self.close()
|
||||
raise GeneralProxyError((1, _generalerrors[1]))
|
||||
# Check the chosen authentication method
|
||||
if chosenauth[1:2] == chr(0x00).encode():
|
||||
# No authentication is required
|
||||
pass
|
||||
elif chosenauth[1:2] == chr(0x02).encode():
|
||||
# Okay, we need to perform a basic username/password
|
||||
# authentication.
|
||||
self.sendall(chr(0x01).encode() + chr(len(self.__proxy[4])) + self.__proxy[4] + chr(len(self.__proxy[5])) + self.__proxy[5])
|
||||
authstat = self.__recvall(2)
|
||||
if authstat[0:1] != chr(0x01).encode():
|
||||
# Bad response
|
||||
self.close()
|
||||
raise GeneralProxyError((1, _generalerrors[1]))
|
||||
if authstat[1:2] != chr(0x00).encode():
|
||||
# Authentication failed
|
||||
self.close()
|
||||
raise Socks5AuthError((3, _socks5autherrors[3]))
|
||||
# Authentication succeeded
|
||||
else:
|
||||
# Reaching here is always bad
|
||||
self.close()
|
||||
if chosenauth[1] == chr(0xFF).encode():
|
||||
raise Socks5AuthError((2, _socks5autherrors[2]))
|
||||
else:
|
||||
raise GeneralProxyError((1, _generalerrors[1]))
|
||||
# Now we can request the actual connection
|
||||
req = struct.pack('BBB', 0x05, 0x01, 0x00)
|
||||
# If the given destination address is an IP address, we'll
|
||||
# use the IPv4 address request even if remote resolving was specified.
|
||||
try:
|
||||
ipaddr = socket.inet_aton(destaddr)
|
||||
req = req + chr(0x01).encode() + ipaddr
|
||||
except socket.error:
|
||||
# Well it's not an IP number, so it's probably a DNS name.
|
||||
if self.__proxy[3]:
|
||||
# Resolve remotely
|
||||
ipaddr = None
|
||||
req = req + chr(0x03).encode() + chr(len(destaddr)).encode() + destaddr
|
||||
else:
|
||||
# Resolve locally
|
||||
ipaddr = socket.inet_aton(socket.gethostbyname(destaddr))
|
||||
req = req + chr(0x01).encode() + ipaddr
|
||||
req = req + struct.pack(">H", destport)
|
||||
self.sendall(req)
|
||||
# Get the response
|
||||
resp = self.__recvall(4)
|
||||
if resp[0:1] != chr(0x05).encode():
|
||||
self.close()
|
||||
raise GeneralProxyError((1, _generalerrors[1]))
|
||||
elif resp[1:2] != chr(0x00).encode():
|
||||
# Connection failed
|
||||
self.close()
|
||||
if ord(resp[1:2])<=8:
|
||||
raise Socks5Error((ord(resp[1:2]), _socks5errors[ord(resp[1:2])]))
|
||||
else:
|
||||
raise Socks5Error((9, _socks5errors[9]))
|
||||
# Get the bound address/port
|
||||
elif resp[3:4] == chr(0x01).encode():
|
||||
boundaddr = self.__recvall(4)
|
||||
elif resp[3:4] == chr(0x03).encode():
|
||||
resp = resp + self.recv(1)
|
||||
boundaddr = self.__recvall(ord(resp[4:5]))
|
||||
else:
|
||||
self.close()
|
||||
raise GeneralProxyError((1,_generalerrors[1]))
|
||||
boundport = struct.unpack(">H", self.__recvall(2))[0]
|
||||
self.__proxysockname = (boundaddr, boundport)
|
||||
if ipaddr != None:
|
||||
self.__proxypeername = (socket.inet_ntoa(ipaddr), destport)
|
||||
else:
|
||||
self.__proxypeername = (destaddr, destport)
|
||||
|
||||
def getproxysockname(self):
|
||||
"""getsockname() -> address info
|
||||
Returns the bound IP address and port number at the proxy.
|
||||
"""
|
||||
return self.__proxysockname
|
||||
|
||||
def getproxypeername(self):
|
||||
"""getproxypeername() -> address info
|
||||
Returns the IP and port number of the proxy.
|
||||
"""
|
||||
return _orgsocket.getpeername(self)
|
||||
|
||||
def getpeername(self):
|
||||
"""getpeername() -> address info
|
||||
Returns the IP address and port number of the destination
|
||||
machine (note: getproxypeername returns the proxy)
|
||||
"""
|
||||
return self.__proxypeername
|
||||
|
||||
def __negotiatesocks4(self,destaddr,destport):
|
||||
"""__negotiatesocks4(self,destaddr,destport)
|
||||
Negotiates a connection through a SOCKS4 server.
|
||||
"""
|
||||
# Check if the destination address provided is an IP address
|
||||
rmtrslv = False
|
||||
try:
|
||||
ipaddr = socket.inet_aton(destaddr)
|
||||
except socket.error:
|
||||
# It's a DNS name. Check where it should be resolved.
|
||||
if self.__proxy[3]:
|
||||
ipaddr = struct.pack("BBBB", 0x00, 0x00, 0x00, 0x01)
|
||||
rmtrslv = True
|
||||
else:
|
||||
ipaddr = socket.inet_aton(socket.gethostbyname(destaddr))
|
||||
# Construct the request packet
|
||||
req = struct.pack(">BBH", 0x04, 0x01, destport) + ipaddr
|
||||
# The username parameter is considered userid for SOCKS4
|
||||
if self.__proxy[4] != None:
|
||||
req = req + self.__proxy[4]
|
||||
req = req + chr(0x00).encode()
|
||||
# DNS name if remote resolving is required
|
||||
# NOTE: This is actually an extension to the SOCKS4 protocol
|
||||
# called SOCKS4A and may not be supported in all cases.
|
||||
if rmtrslv:
|
||||
req = req + destaddr + chr(0x00).encode()
|
||||
self.sendall(req)
|
||||
# Get the response from the server
|
||||
resp = self.__recvall(8)
|
||||
if resp[0:1] != chr(0x00).encode():
|
||||
# Bad data
|
||||
self.close()
|
||||
raise GeneralProxyError((1,_generalerrors[1]))
|
||||
if resp[1:2] != chr(0x5A).encode():
|
||||
# Server returned an error
|
||||
self.close()
|
||||
if ord(resp[1:2]) in (91, 92, 93):
|
||||
self.close()
|
||||
raise Socks4Error((ord(resp[1:2]), _socks4errors[ord(resp[1:2]) - 90]))
|
||||
else:
|
||||
raise Socks4Error((94, _socks4errors[4]))
|
||||
# Get the bound address/port
|
||||
self.__proxysockname = (socket.inet_ntoa(resp[4:]), struct.unpack(">H", resp[2:4])[0])
|
||||
if rmtrslv != None:
|
||||
self.__proxypeername = (socket.inet_ntoa(ipaddr), destport)
|
||||
else:
|
||||
self.__proxypeername = (destaddr, destport)
|
||||
|
||||
def __negotiatehttp(self, destaddr, destport):
|
||||
"""__negotiatehttp(self,destaddr,destport)
|
||||
Negotiates a connection through an HTTP server.
|
||||
"""
|
||||
# If we need to resolve locally, we do this now
|
||||
if not self.__proxy[3]:
|
||||
addr = socket.gethostbyname(destaddr)
|
||||
else:
|
||||
addr = destaddr
|
||||
self.sendall(("CONNECT " + addr + ":" + str(destport) + " HTTP/1.1\r\n" + "Host: " + destaddr + "\r\n\r\n").encode())
|
||||
# We read the response until we get the string "\r\n\r\n"
|
||||
resp = self.recv(1)
|
||||
while resp.find("\r\n\r\n".encode()) == -1:
|
||||
resp = resp + self.recv(1)
|
||||
# We just need the first line to check if the connection
|
||||
# was successful
|
||||
statusline = resp.splitlines()[0].split(" ".encode(), 2)
|
||||
if statusline[0] not in ("HTTP/1.0".encode(), "HTTP/1.1".encode()):
|
||||
self.close()
|
||||
raise GeneralProxyError((1, _generalerrors[1]))
|
||||
try:
|
||||
statuscode = int(statusline[1])
|
||||
except ValueError:
|
||||
self.close()
|
||||
raise GeneralProxyError((1, _generalerrors[1]))
|
||||
if statuscode != 200:
|
||||
self.close()
|
||||
raise HTTPError((statuscode, statusline[2]))
|
||||
self.__proxysockname = ("0.0.0.0", 0)
|
||||
self.__proxypeername = (addr, destport)
|
||||
|
||||
def connect(self, destpair):
|
||||
"""connect(self, despair)
|
||||
Connects to the specified destination through a proxy.
|
||||
destpar - A tuple of the IP/DNS address and the port number.
|
||||
(identical to socket's connect).
|
||||
To select the proxy server use setproxy().
|
||||
"""
|
||||
# Do a minimal input check first
|
||||
if (not type(destpair) in (list,tuple)) or (len(destpair) < 2) or (type(destpair[0]) != type('')) or (type(destpair[1]) != int):
|
||||
raise GeneralProxyError((5, _generalerrors[5]))
|
||||
if self.__proxy[0] == PROXY_TYPE_SOCKS5:
|
||||
if self.__proxy[2] != None:
|
||||
portnum = self.__proxy[2]
|
||||
else:
|
||||
portnum = 1080
|
||||
_orgsocket.connect(self, (self.__proxy[1], portnum))
|
||||
self.__negotiatesocks5(destpair[0], destpair[1])
|
||||
elif self.__proxy[0] == PROXY_TYPE_SOCKS4:
|
||||
if self.__proxy[2] != None:
|
||||
portnum = self.__proxy[2]
|
||||
else:
|
||||
portnum = 1080
|
||||
_orgsocket.connect(self,(self.__proxy[1], portnum))
|
||||
self.__negotiatesocks4(destpair[0], destpair[1])
|
||||
elif self.__proxy[0] == PROXY_TYPE_HTTP:
|
||||
if self.__proxy[2] != None:
|
||||
portnum = self.__proxy[2]
|
||||
else:
|
||||
portnum = 8080
|
||||
_orgsocket.connect(self,(self.__proxy[1], portnum))
|
||||
self.__negotiatehttp(destpair[0], destpair[1])
|
||||
elif self.__proxy[0] == None:
|
||||
_orgsocket.connect(self, (destpair[0], destpair[1]))
|
||||
else:
|
||||
raise GeneralProxyError((4, _generalerrors[4]))
|
|
@ -347,15 +347,16 @@ class Wallet:
|
|||
def is_up_to_date(self):
|
||||
return self.interface.responses.empty() and not self.interface.unanswered_requests
|
||||
|
||||
def set_server(self, server):
|
||||
def set_server(self, server, proxy):
|
||||
# raise an error if the format isnt correct
|
||||
a,b,c = server.split(':')
|
||||
b = int(b)
|
||||
assert c in ['t', 'h', 'n']
|
||||
# set the server
|
||||
if server != self.server:
|
||||
if server != self.server or proxy != self.interface.proxy:
|
||||
self.server = server
|
||||
self.save()
|
||||
self.interface.proxy = proxy
|
||||
self.interface.is_connected = False # this exits the polling loop
|
||||
self.interface.poke()
|
||||
|
||||
|
|
1
setup.py
1
setup.py
|
@ -55,6 +55,7 @@ setup(name = "Electrum",
|
|||
'electrum.qrscanner',
|
||||
'electrum.history_widget',
|
||||
'electrum.simple_config',
|
||||
'electrum.socks',
|
||||
'electrum.bmp',
|
||||
'electrum.msqr',
|
||||
'electrum.util',
|
||||
|
|
Loading…
Add table
Reference in a new issue