From aa6f631f2e14391229425c5ffba1a07f4dd471be Mon Sep 17 00:00:00 2001 From: bkkcoins Date: Wed, 19 Sep 2012 17:37:20 +0700 Subject: [PATCH] Added SOCKS support, with cmdline and SimpleConfig options --- electrum | 9 +++++--- lib/__init__.py | 2 +- lib/interface.py | 50 +++++++++++++++++++++++++++++++++++--------- lib/simple_config.py | 2 +- 4 files changed, 48 insertions(+), 15 deletions(-) diff --git a/electrum b/electrum index 32ec670fe..fde255bc1 100755 --- a/electrum +++ b/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: diff --git a/lib/__init__.py b/lib/__init__.py index a9461ac88..3618ccfe3 100644 --- a/lib/__init__.py +++ b/lib/__init__.py @@ -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 diff --git a/lib/interface.py b/lib/interface.py index 6a28cf8e6..185a2d47e 100644 --- a/lib/interface.py +++ b/lib/interface.py @@ -29,6 +29,7 @@ DEFAULT_SERVERS = [ 'ecdsa.org:50001:t', 'uncle-enzo.info:50001:t', 'electrum.bytesized-hosting.com:50001:t'] # list of default servers +proxy_modes = ['off', 'socks4', 'socks5', 'http' ] def replace_keys(obj, old_key, new_key): if isinstance(obj, dict): @@ -48,13 +49,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 @@ -122,8 +139,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 @@ -174,7 +191,11 @@ class HttpStratumInterface(PollingInterface): def send(self, messages): import urllib2, json, time, cookielib - + + if self.proxy["mode"] != "off": + 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) @@ -233,16 +254,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"] == "off": + 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) @@ -306,13 +334,15 @@ 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 + def init_interface(self): try: @@ -332,7 +362,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): diff --git a/lib/simple_config.py b/lib/simple_config.py index 06f78bdc1..3ade03305 100644 --- a/lib/simple_config.py +++ b/lib/simple_config.py @@ -3,7 +3,7 @@ import os from util import user_dir class SimpleConfig: - default_options = {"gui": "lite"} + default_options = {"gui": "lite", "proxy": { "mode": "off", "host":"localhost", "port":"8080" } } def set_key(self, key, value, save = True): self.config[key] = value