tadd option to disable dnssec - electrum - Electrum Bitcoin wallet HTML git clone https://git.parazyd.org/electrum DIR Log DIR Files DIR Refs DIR Submodules --- DIR commit a3cd33fe0364b326365b86f62424a212d03e87d0 DIR parent 9be94c74d25e6ae4dc4956e4bf506d8f31e7280d HTML Author: ThomasV <thomasv@gitorious> Date: Sun, 31 May 2015 16:43:27 +0200 add option to disable dnssec Diffstat: M lib/commands.py | 44 ++++++++++++++++--------------- M lib/util.py | 10 ++++++---- M plugins/openalias.py | 27 +++++++++++++++++++++------ 3 files changed, 50 insertions(+), 31 deletions(-) --- DIR diff --git a/lib/commands.py b/lib/commands.py t@@ -65,7 +65,7 @@ register_command('decodetx', 0, 0, 0, ['tx'], [], 'Decode serialized t register_command('getprivatekeys', 0, 1, 1, ['address'], [], 'Get the private keys of an address', 'Address must be in wallet.') register_command('dumpprivkeys', 0, 1, 1, [], [], 'Dump private keys from your wallet', '') register_command('freeze', 0, 1, 0, ['address'], [], 'Freeze address', 'Freeze the funds at one of your wallet\'s addresses') -register_command('getalias', 0, 0, 0, ['key'], [], 'Retrieve alias', 'Lookup in your list of contacts, and for an OpenAlias DNS record') +register_command('getalias', 0, 0, 0, ['key'], ['nocheck'], 'Retrieve alias', 'Lookup in your list of contacts, and for an OpenAlias DNS record') register_command('getbalance', 1, 1, 0, [], [], 'Return the balance of your wallet', '') register_command('getservers', 1, 0, 0, [], [], 'Return the list of available servers', '') register_command('getaddressbalance', 1, 0, 0, ['address'], [], 'Return the balance of an address', '') t@@ -83,10 +83,10 @@ register_command('listaddresses', 0, 1, 0, [], ['show_all', 'show_labels', 'List wallet addresses', 'Returns your list of addresses.') register_command('listunspent', 1, 1, 0, [], [], 'List unspent outputs', 'Returns the list of unspent transaction outputs in your wallet.') register_command('getaddressunspent', 1, 0, 0, ['address'], [], 'Returns the list of unspent inputs for an address', '') -register_command('mktx', 0, 1, 1, ['address', 'amount'], ['tx_fee', 'from_addr', 'change_addr'], 'Create signed transaction', '') -register_command('payto', 1, 1, 1, ['address', 'amount'], ['tx_fee', 'from_addr', 'change_addr'], 'Create and broadcast a transaction.', '') -register_command('mktx_csv', 0, 1, 1, ['csv_file'], ['tx_fee', 'from_addr', 'change_addr'], 'Create a signed transaction', '') -register_command('payto_csv', 1, 1, 1, ['csv_file'], ['tx_fee', 'from_addr', 'change_addr'], 'Create and broadcast a transaction.', '') +register_command('mktx', 0, 1, 1, ['address', 'amount'], ['tx_fee', 'from_addr', 'change_addr', 'nocheck'], 'Create signed transaction', '') +register_command('payto', 1, 1, 1, ['address', 'amount'], ['tx_fee', 'from_addr', 'change_addr', 'nocheck'], 'Create and broadcast a transaction.', '') +register_command('mktx_csv', 0, 1, 1, ['csv_file'], ['tx_fee', 'from_addr', 'change_addr', 'nocheck'], 'Create a signed transaction', '') +register_command('payto_csv', 1, 1, 1, ['csv_file'], ['tx_fee', 'from_addr', 'change_addr', 'nocheck'], 'Create and broadcast a transaction.', '') register_command('password', 0, 1, 1, [], [], 'Change your password', '') register_command('restore', 1, 1, 0, [], ['gap_limit', 'mpk', 'concealed'], 'Restore a wallet from seed', '') register_command('searchcontacts', 0, 1, 0, ['query'], [], 'Search through contacts, return matching entries', '') t@@ -137,6 +137,7 @@ command_options = { 'funded': (None, "--funded", False, "Show only funded addresses"), 'show_balance':("-b", "--balance", False, "Show the balances of listed addresses"), 'show_labels': ("-l", "--labels", False, "Show the labels of listed addresses"), + 'nocheck': (None, "--nocheck", False, "Do not verify aliases"), 'tx_fee': ("-f", "--fee", None, "Transaction fee (in BTC)"), 'from_addr': ("-F", "--from", None, "Source address. 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."), 'change_addr': ("-c", "--change", None, "Change address. Default is a spare address, or the source address if it's not in the wallet"), t@@ -427,13 +428,14 @@ class Commands: def verifymessage(self, address, signature, message): return bitcoin.verify_message(address, signature, message) - def _mktx(self, outputs, fee=None, change_addr=None, domain=None): - change_addr = None if change_addr is None else self.contacts.resolve(change_addr) - domain = None if domain is None else map(self.contacts.resolve, domain) + def _mktx(self, outputs, fee=None, change_addr=None, domain=None, nocheck=False): + resolver = lambda x: None if x is None else self.contacts.resolve(x, nocheck)['address'] + change_addr = resolver(change_addr) + domain = None if domain is None else map(resolver, domain) fee = None if fee is None else int(100000000*Decimal(fee)) final_outputs = [] for address, amount in outputs: - address = self.contacts.resolve(address) + address = resolver(address) #assert self.wallet.is_mine(address) if amount == '!': assert len(outputs) == 1 t@@ -464,28 +466,28 @@ class Commands: outputs.append((address, amount)) return outputs - def mktx(self, to_address, amount, fee=None, from_addr=None, change_addr=None): + def mktx(self, to_address, amount, fee=None, from_addr=None, change_addr=None, nocheck=False): domain = [from_addr] if from_addr else None - tx = self._mktx([(to_address, amount)], fee, change_addr, domain) + tx = self._mktx([(to_address, amount)], fee, change_addr, domain, nocheck) return tx - def mktx_csv(self, path, fee=None, from_addr=None, change_addr=None): + def mktx_csv(self, path, fee=None, from_addr=None, change_addr=None, nocheck=False): domain = [from_addr] if from_addr else None outputs = self._read_csv(path) - tx = self._mktx(outputs, fee, change_addr, domain) + tx = self._mktx(outputs, fee, change_addr, domain, nocheck) return tx - def payto(self, to_address, amount, fee=None, from_addr=None, change_addr=None): + def payto(self, to_address, amount, fee=None, from_addr=None, change_addr=None, nocheck=False): domain = [from_addr] if from_addr else None - tx = self._mktx([(to_address, amount)], fee, change_addr, domain) - r, h = self.wallet.sendtx( tx ) + tx = self._mktx([(to_address, amount)], fee, change_addr, domain, nocheck) + r, h = self.wallet.sendtx(tx) return h - def payto_csv(self, path, fee = None, from_addr=None, change_addr=None): + def payto_csv(self, path, fee = None, from_addr=None, change_addr=None, nocheck=False): domain = [from_addr] if from_addr else None outputs = self._read_csv(path) - tx = self._mktx(outputs, fee, change_addr, domain) - r, h = self.wallet.sendtx( tx ) + tx = self._mktx(outputs, fee, change_addr, domain, nocheck) + r, h = self.wallet.sendtx(tx) return h def history(self): t@@ -509,8 +511,8 @@ class Commands: def listcontacts(self): return self.contacts - def getalias(self, key): - return self.contacts.resolve(key) + def getalias(self, key, nocheck=False): + return self.contacts.resolve(key, nocheck) def searchcontacts(self, query): results = {} DIR diff --git a/lib/util.py b/lib/util.py t@@ -467,18 +467,20 @@ import bitcoin from plugins import run_hook class Contacts(StoreDict): + def __init__(self, config): StoreDict.__init__(self, config, 'contacts') - def resolve(self, k): + def resolve(self, k, nocheck=False): if bitcoin.is_address(k): - return k + return {'address':k, 'type':'address'} if k in self.keys(): _type, addr = self[k] if _type == 'address': - return addr + return {'address':addr, 'type':'contact'} out = run_hook('resolve_address', k) if out: + if not nocheck and out.get('validated') is False: + raise Exception("cannot validate alias") return out raise Exception("invalid Bitcoin address", k) - DIR diff --git a/plugins/openalias.py b/plugins/openalias.py t@@ -181,7 +181,22 @@ class Plugin(BasePlugin): @hook def resolve_address(self, url): - return self.resolve(url)[0] + data = self.resolve(url) + if not data: + return + address, name = data + try: + validated = self.validate_dnssec(url) + except: + validated = False + traceback.print_exc(file=sys.stderr) + return { + 'address': address, + 'name': name, + 'type': 'openalias', + 'validated': validated + } + def resolve(self, url): '''Resolve OpenAlias address using url.''' t@@ -244,7 +259,7 @@ class Plugin(BasePlugin): response = dns.query.udp(query, ns, 3) if response.rcode() != dns.rcode.NOERROR: self.print_error("query error") - return 0 + return False if len(response.authority) > 0: rrset = response.authority[0] t@@ -262,14 +277,14 @@ class Plugin(BasePlugin): response = dns.query.udp(query, ns, 3) if response.rcode() != 0: self.print_error("query error") - return 0 + return False # HANDLE QUERY FAILED (SERVER ERROR OR NO DNSKEY RECORD) # answer should contain two RRSET: DNSKEY and RRSIG(DNSKEY) answer = response.answer if len(answer) != 2: self.print_error("answer error", answer) - return 0 + return False # the DNSKEY should be self signed, validate it name = dns.name.from_text(sub) t@@ -277,6 +292,6 @@ class Plugin(BasePlugin): dns.dnssec.validate(answer[0], answer[1], {name: answer[0]}) except dns.dnssec.ValidationFailure: self.print_error("validation error") - return 0 + return False - return 1 + return True