commit 362ca96f382afd8f8cdb31c123df930eca461f49
parent 0693403358656f1e7d5453679f125ab48d7fb644
Author: Dmitry Sorokin <asfins@gmail.com>
Date: Sun, 5 Feb 2017 13:38:44 +0300
x509 fixes and plugins
Diffstat:
18 files changed, 111 insertions(+), 115 deletions(-)
diff --git a/lib/base_wizard.py b/lib/base_wizard.py
@@ -189,7 +189,7 @@ class BaseWizard(object):
except:
devmgr.print_error("error", name)
continue
- devices += map(lambda x: (name, x), u)
+ devices += list(map(lambda x: (name, x), u))
if not devices:
msg = ''.join([
_('No hardware device detected.') + '\n',
@@ -235,7 +235,7 @@ class BaseWizard(object):
self.line_dialog(run_next=f, title=_('Derivation'), message=message, default=default, test=bitcoin.is_bip32_derivation)
def on_hw_derivation(self, name, device_info, derivation):
- from keystore import hardware_keystore
+ from .keystore import hardware_keystore
xpub = self.plugin.get_xpub(device_info.device.id_, derivation, self)
if xpub is None:
self.show_error('Cannot read xpub from device')
@@ -286,7 +286,7 @@ class BaseWizard(object):
self.load_2fa()
self.run('on_restore_seed', seed, is_ext)
else:
- raise BaseException('Unknown seed type', seed_type)
+ raise BaseException('Unknown seed type', self.seed_type)
def on_restore_bip39(self, seed, passphrase):
f = lambda x: self.run('on_bip44', seed, passphrase, str(x))
@@ -334,7 +334,8 @@ class BaseWizard(object):
k.update_password(None, password)
if self.wallet_type == 'standard':
self.storage.put('seed_type', self.seed_type)
- self.storage.put('keystore', k.dump())
+ keys = self.keystores[0].dump()
+ self.storage.put('keystore', keys)
self.wallet = Standard_Wallet(self.storage)
self.run('create_addresses')
elif self.wallet_type == 'multisig':
@@ -355,7 +356,7 @@ class BaseWizard(object):
self.on_keystore(k)
def create_seed(self):
- import mnemonic
+ from . import mnemonic
self.seed_type = 'segwit' if bitcoin.TESTNET and self.config.get('segwit') else 'standard'
seed = mnemonic.Mnemonic('en').make_seed(self.seed_type)
self.opt_bip39 = False
diff --git a/lib/bitcoin.py b/lib/bitcoin.py
@@ -29,7 +29,7 @@ import re
import hmac
import os
-from lib.util import bfh, bh2u
+from lib.util import bfh, bh2u, to_string
from . import version
from .util import print_error, InvalidPassword, assert_bytes, to_bytes
@@ -150,7 +150,7 @@ def DecodeAES(secret, e):
def pw_encode(s, password):
if password:
secret = Hash(password)
- return EncodeAES(secret, s.encode("utf8"))
+ return EncodeAES(secret, to_bytes(s, "utf8"))
else:
return s
@@ -158,7 +158,7 @@ def pw_decode(s, password):
if password is not None:
secret = Hash(password)
try:
- d = DecodeAES(secret, s).decode("utf8")
+ d = to_string(DecodeAES(secret, s), "utf8")
except Exception:
raise InvalidPassword()
return d
@@ -213,7 +213,7 @@ def Hash(x):
hash_encode = lambda x: bh2u(x[::-1])
hash_decode = lambda x: bfh(x)[::-1]
-hmac_sha_512 = lambda x, y: _bytes(hmac.new(x, y, hashlib.sha512).digest())
+hmac_sha_512 = lambda x, y: hmac.new(x, y, hashlib.sha512).digest()
def is_new_seed(x, prefix=version.SEED_PREFIX):
diff --git a/lib/daemon.py b/lib/daemon.py
@@ -34,8 +34,8 @@ import sys
import time
# from jsonrpc import JSONRPCResponseManager
-import jsonrpclib
-from jsonrpclib.SimpleJSONRPCServer import SimpleJSONRPCServer, SimpleJSONRPCRequestHandler
+# import jsonrpclib
+# from jsonrpclib.SimpleJSONRPCServer import SimpleJSONRPCServer, SimpleJSONRPCRequestHandler
from .version import ELECTRUM_VERSION
from .network import Network
@@ -96,17 +96,17 @@ def get_server(config):
time.sleep(1.0)
-class RequestHandler(SimpleJSONRPCRequestHandler):
-
- def do_OPTIONS(self):
- self.send_response(200)
- self.end_headers()
-
- def end_headers(self):
- self.send_header("Access-Control-Allow-Headers",
- "Origin, X-Requested-With, Content-Type, Accept")
- self.send_header("Access-Control-Allow-Origin", "*")
- SimpleJSONRPCRequestHandler.end_headers(self)
+# class RequestHandler(SimpleJSONRPCRequestHandler):
+#
+# def do_OPTIONS(self):
+# self.send_response(200)
+# self.end_headers()
+#
+# def end_headers(self):
+# self.send_header("Access-Control-Allow-Headers",
+# "Origin, X-Requested-With, Content-Type, Accept")
+# self.send_header("Access-Control-Allow-Origin", "*")
+# SimpleJSONRPCRequestHandler.end_headers(self)
class Daemon(DaemonThread):
@@ -132,24 +132,24 @@ class Daemon(DaemonThread):
def init_server(self, config, fd):
host = config.get('rpchost', '127.0.0.1')
port = config.get('rpcport', 0)
- try:
- server = SimpleJSONRPCServer((host, port), logRequests=False,
- requestHandler=RequestHandler)
- except Exception as e:
- self.print_error('Warning: cannot initialize RPC server on host', host, e)
- self.server = None
- os.close(fd)
- return
- os.write(fd, bytes(repr((server.socket.getsockname(), time.time())), 'utf8'))
- os.close(fd)
- server.timeout = 0.1
- for cmdname in known_commands:
- server.register_function(getattr(self.cmd_runner, cmdname), cmdname)
- server.register_function(self.run_cmdline, 'run_cmdline')
- server.register_function(self.ping, 'ping')
- server.register_function(self.run_daemon, 'daemon')
- server.register_function(self.run_gui, 'gui')
- self.server = server
+ # try:
+ # server = SimpleJSONRPCServer((host, port), logRequests=False, requestHandler=RequestHandler)
+ # except Exception as e:
+ # self.print_error('Warning: cannot initialize RPC server on host', host, e)
+ # self.server = None
+ # os.close(fd)
+ # return
+ # os.write(fd, bytes(repr((server.socket.getsockname(), time.time())), 'utf8'))
+ # os.close(fd)
+ # server.timeout = 0.1
+ # for cmdname in known_commands:
+ # server.register_function(getattr(self.cmd_runner, cmdname), cmdname)
+ # server.register_function(self.run_cmdline, 'run_cmdline')
+ # server.register_function(self.ping, 'ping')
+ # server.register_function(self.run_daemon, 'daemon')
+ # server.register_function(self.run_gui, 'gui')
+ # self.server = server
+ self.server = None
def ping(self):
return True
@@ -260,9 +260,9 @@ class Daemon(DaemonThread):
# arguments passed to function
args = map(lambda x: config.get(x), cmd.params)
# decode json arguments
- args = map(json_decode, args)
+ args = [json_decode(i) for i in args]
# options
- args += map(lambda x: (config_options.get(x) if x in ['password', 'new_password'] else config.get(x)), cmd.options)
+ args += list(map(lambda x: (config_options.get(x) if x in ['password', 'new_password'] else config.get(x)), cmd.options))
cmd_runner = Commands(config, wallet, self.network)
func = getattr(cmd_runner, cmd.name)
result = func(*args)
diff --git a/lib/keystore.py b/lib/keystore.py
@@ -149,7 +149,7 @@ class Imported_KeyStore(Software_KeyStore):
except Exception:
raise BaseException('Invalid private key')
# allow overwrite
- self.keypairs[pubkey] = pw_encode(sec, password)
+ self.keypairs[pubkey] = pw_encode(sec, password).decode('ascii')
return pubkey
def delete_imported_key(self, key):
@@ -179,7 +179,7 @@ class Imported_KeyStore(Software_KeyStore):
new_password = None
for k, v in self.keypairs.items():
b = pw_decode(v, old_password)
- c = pw_encode(b, new_password)
+ c = pw_encode(b, new_password).decode('ascii')
self.keypairs[k] = c
@@ -309,13 +309,13 @@ class BIP32_KeyStore(Deterministic_KeyStore, Xpub):
new_password = None
if self.has_seed():
decoded = self.get_seed(old_password)
- self.seed = pw_encode(decoded, new_password)
+ self.seed = pw_encode(decoded, new_password).decode('ascii')
if self.passphrase:
decoded = self.get_passphrase(old_password)
- self.passphrase = pw_encode(decoded, new_password)
+ self.passphrase = pw_encode(decoded, new_password).decode('ascii')
if self.xprv is not None:
b = pw_decode(self.xprv, old_password)
- self.xprv = pw_encode(b, new_password)
+ self.xprv = pw_encode(b, new_password).decode('ascii')
def is_watching_only(self):
return self.xprv is None
@@ -478,7 +478,7 @@ class Old_KeyStore(Deterministic_KeyStore):
new_password = None
if self.has_seed():
decoded = self.get_hex_seed(old_password)
- self.seed = pw_encode(decoded, new_password)
+ self.seed = pw_encode(decoded, new_password).decode('ascii')
class Hardware_KeyStore(KeyStore, Xpub):
diff --git a/lib/mnemonic.py b/lib/mnemonic.py
@@ -173,7 +173,7 @@ class Mnemonic(object):
return i % custom_entropy == 0
def make_seed(self, seed_type='standard', num_bits=132, custom_entropy=1):
- import version
+ from . import version
prefix = version.seed_prefix(seed_type)
# increase num_bits in order to obtain a uniform distibution for the last word
bpw = math.log(len(self.wordlist), 2)
diff --git a/lib/paymentrequest.py b/lib/paymentrequest.py
@@ -345,7 +345,6 @@ def sign_request_with_alias(pr, alias, alias_privkey):
pr.signature = ec_key.sign_message(message, compressed, address)
-
def verify_cert_chain(chain):
""" Verify a chain of certificates. The last certificate is the CA"""
load_ca_list()
diff --git a/lib/pem.py b/lib/pem.py
@@ -127,12 +127,12 @@ def pem(b, name):
-----END CERTIFICATE-----
"""
s1 = b2a_base64(b)[:-1] # remove terminating \n
- s2 = ""
+ s2 = b""
while s1:
- s2 += s1[:64] + "\n"
+ s2 += s1[:64] + b"\n"
s1 = s1[64:]
- s = ("-----BEGIN %s-----\n" % name) + s2 + \
- ("-----END %s-----\n" % name)
+ s = ("-----BEGIN %s-----\n" % name).encode('ascii') + s2 + \
+ ("-----END %s-----\n" % name).encode('ascii')
return s
def pemSniff(inStr, name):
@@ -152,8 +152,8 @@ def parse_private_key(s):
raise SyntaxError("Not a PEM private key file")
-def _parsePKCS8(bytes):
- s = ASN1_Node(str(bytes))
+def _parsePKCS8(_bytes):
+ s = ASN1_Node(_bytes)
root = s.root()
version_node = s.first_child(root)
version = bytestr_to_int(s.get_value_of_type(version_node, 'INTEGER'))
@@ -192,5 +192,5 @@ def _parseASN1PrivateKey(s):
dP = s.next_node(q)
dQ = s.next_node(dP)
qInv = s.next_node(dQ)
- return map(lambda x: bytesToNumber(s.get_value_of_type(x, 'INTEGER')), [n, e, d, p, q, dP, dQ, qInv])
+ return list(map(lambda x: bytesToNumber(s.get_value_of_type(x, 'INTEGER')), [n, e, d, p, q, dP, dQ, qInv]))
diff --git a/lib/plugins.py b/lib/plugins.py
@@ -22,12 +22,6 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
-from __future__ import absolute_import
-from __future__ import division
-from __future__ import print_function
-from __future__ import unicode_literals
-
-import six
from collections import namedtuple
import traceback
import sys
@@ -192,7 +186,7 @@ class Plugins(DaemonThread):
def hook(func):
- hook_names.add(func.func_name)
+ hook_names.add(func.__name__)
return func
def run_hook(name, *args):
diff --git a/lib/storage.py b/lib/storage.py
@@ -22,12 +22,6 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
-from __future__ import absolute_import
-from __future__ import division
-from __future__ import print_function
-from __future__ import unicode_literals
-
-import six
import os
import ast
import threading
diff --git a/lib/util.py b/lib/util.py
@@ -586,7 +586,8 @@ def parse_URI(uri, on_pr=None):
request = pr.PaymentRequest(s)
else:
request = pr.get_payment_request(r)
- on_pr(request)
+ if on_pr:
+ on_pr(request)
t = threading.Thread(target=get_payment_request_thread)
t.setDaemon(True)
t.start()
@@ -698,7 +699,6 @@ class SocketPipe:
self._send(out)
def send_all(self, requests):
- print(requests)
out = b''.join(map(lambda x: (json.dumps(x) + '\n').encode('utf8'), requests))
self._send(out)
diff --git a/lib/wallet.py b/lib/wallet.py
@@ -1537,8 +1537,6 @@ class Deterministic_Wallet(Abstract_Wallet):
return self.get_master_public_key()
-
-
class Simple_Wallet(Abstract_Wallet):
""" Wallet with a single pubkey per address """
diff --git a/lib/x509.py b/lib/x509.py
@@ -63,6 +63,7 @@ ASN1_TYPES = {
'PrintableString' : 0x13,
'IA5String' : 0x16,
'UTCTime' : 0x17,
+ 'GeneralizedTime' : 0x18,
'ENUMERATED' : 0x0A,
'UTF8String' : 0x0C,
}
@@ -75,7 +76,7 @@ class CertificateError(Exception):
# helper functions
def bitstr_to_bytestr(s):
if s[0] != 0x00:
- raise BaseException('no padding')
+ raise TypeError('no padding')
return s[1:]
@@ -117,7 +118,7 @@ class ASN1_Node(bytes):
def get_node(self, ix):
# return index of first byte, first content byte and last byte.
first = self[ix + 1]
- if (self[ix + 1] & 0x80) == 0:
+ if (first & 0x80) == 0:
length = first
ixf = ix + 2
ixl = ixf + length - 1
@@ -138,7 +139,7 @@ class ASN1_Node(bytes):
def first_child(self, node):
ixs, ixf, ixl = node
if self[ixs] & 0x20 != 0x20:
- raise BaseException('Can only open constructed types.', hex(self[ixs]))
+ raise TypeError('Can only open constructed types.', hex(self[ixs]))
return self.get_node(ixf)
def is_child_of(node1, node2):
@@ -155,7 +156,7 @@ class ASN1_Node(bytes):
# verify type byte and return content
ixs, ixf, ixl = node
if ASN1_TYPES[asn1_type] != self[ixs]:
- raise BaseException('Wrong type:', hex(self[ixs]), hex(ASN1_TYPES[asn1_type]))
+ raise TypeError('Wrong type:', hex(self[ixs]), hex(ASN1_TYPES[asn1_type]))
return self[ixf:ixl + 1]
def get_value(self, node):
@@ -217,9 +218,15 @@ class X509(object):
# validity
validity = der.next_node(issuer)
ii = der.first_child(validity)
- self.notBefore = der.get_value_of_type(ii, 'UTCTime')
+ try:
+ self.notBefore = der.get_value_of_type(ii, 'UTCTime')
+ except TypeError:
+ self.notBefore = der.get_value_of_type(ii, 'GeneralizedTime')[2:] # strip year
ii = der.next_node(ii)
- self.notAfter = der.get_value_of_type(ii, 'UTCTime')
+ try:
+ self.notAfter = der.get_value_of_type(ii, 'UTCTime')
+ except TypeError:
+ self.notAfter = der.get_value_of_type(ii, 'GeneralizedTime')[2:] # strip year
# subject
subject = der.next_node(validity)
@@ -229,17 +236,22 @@ class X509(object):
ii = der.first_child(public_key_algo)
self.public_key_algo = decode_OID(der.get_value_of_type(ii, 'OBJECT IDENTIFIER'))
- # pubkey modulus and exponent
- subject_public_key = der.next_node(public_key_algo)
- spk = der.get_value_of_type(subject_public_key, 'BIT STRING')
- spk = ASN1_Node(bitstr_to_bytestr(spk))
- r = spk.root()
- modulus = spk.first_child(r)
- exponent = spk.next_node(modulus)
- rsa_n = spk.get_value_of_type(modulus, 'INTEGER')
- rsa_e = spk.get_value_of_type(exponent, 'INTEGER')
- self.modulus = ecdsa.util.string_to_number(rsa_n)
- self.exponent = ecdsa.util.string_to_number(rsa_e)
+ if self.public_key_algo != '1.2.840.10045.2.1': # for non EC public key
+ # pubkey modulus and exponent
+ subject_public_key = der.next_node(public_key_algo)
+ spk = der.get_value_of_type(subject_public_key, 'BIT STRING')
+ spk = ASN1_Node(bitstr_to_bytestr(spk))
+ r = spk.root()
+ modulus = spk.first_child(r)
+ exponent = spk.next_node(modulus)
+ rsa_n = spk.get_value_of_type(modulus, 'INTEGER')
+ rsa_e = spk.get_value_of_type(exponent, 'INTEGER')
+ self.modulus = ecdsa.util.string_to_number(rsa_n)
+ self.exponent = ecdsa.util.string_to_number(rsa_e)
+ else:
+ subject_public_key = der.next_node(public_key_algo)
+ spk = der.get_value_of_type(subject_public_key, 'BIT STRING')
+ self.ec_public_key = spk
# extensions
self.CA = False
@@ -308,14 +320,17 @@ def load_certificates(ca_path):
from . import pem
ca_list = {}
ca_keyID = {}
- with open(ca_path, 'rb') as f:
- s = f.read().decode('ascii')
+ # ca_path = '/tmp/tmp.txt'
+ with open(ca_path, 'r') as f:
+ s = f.read()
bList = pem.dePemList(s, "CERTIFICATE")
for b in bList:
try:
x = X509(b)
x.check_date()
except BaseException as e:
+ # with open('/tmp/tmp.txt', 'w') as f:
+ # f.write(pem.pem(b, 'CERTIFICATE').decode('ascii'))
util.print_error("cert error:", e)
continue
diff --git a/plugins/cosigner_pool/qt.py b/plugins/cosigner_pool/qt.py
@@ -26,7 +26,7 @@
import socket
import threading
import time
-import xmlrpclib
+from xmlrpc.client import ServerProxy
from PyQt4.QtGui import *
from PyQt4.QtCore import *
@@ -45,7 +45,7 @@ import traceback
PORT = 12344
HOST = 'cosigner.electrum.org'
-server = xmlrpclib.ServerProxy('http://%s:%d'%(HOST,PORT), allow_none=True)
+server = ServerProxy('http://%s:%d'%(HOST,PORT), allow_none=True)
class Listener(util.DaemonThread):
diff --git a/plugins/email_requests/qt.py b/plugins/email_requests/qt.py
@@ -23,8 +23,6 @@
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
-from __future__ import absolute_import
-
import time
import threading
import base64
@@ -33,9 +31,9 @@ from functools import partial
import smtplib
import imaplib
import email
-from email.MIMEMultipart import MIMEMultipart
-from email.MIMEBase import MIMEBase
-from email import Encoders
+from email.mime.multipart import MIMEMultipart
+from email.mime.base import MIMEBase
+from email.encoders import encode_base64
from PyQt4.QtGui import *
from PyQt4.QtCore import *
@@ -49,7 +47,6 @@ from electrum_gui.qt.util import EnterButton, Buttons, CloseButton
from electrum_gui.qt.util import OkButton, WindowModalDialog
-
class Processor(threading.Thread):
polling_interval = 5*60
@@ -96,7 +93,7 @@ class Processor(threading.Thread):
msg['From'] = self.username
part = MIMEBase('application', "bitcoin-paymentrequest")
part.set_payload(payment_request)
- Encoders.encode_base64(part)
+ encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="payreq.btc"')
msg.attach(part)
s = smtplib.SMTP_SSL(self.imap_server, timeout=2)
diff --git a/plugins/hw_wallet/__init__.py b/plugins/hw_wallet/__init__.py
@@ -1 +1 @@
-from plugin import HW_PluginBase
+from .plugin import HW_PluginBase
diff --git a/plugins/labels/labels.py b/plugins/labels/labels.py
@@ -12,8 +12,6 @@ from electrum.plugins import BasePlugin, hook
from electrum.i18n import _
-
-
class LabelsPlugin(BasePlugin):
def __init__(self, parent, config, name):
@@ -83,7 +81,7 @@ class LabelsPlugin(BasePlugin):
bundle = {"labels": [],
"walletId": wallet_id,
"walletNonce": self.get_nonce(wallet)}
- for key, value in wallet.labels.iteritems():
+ for key, value in wallet.labels.items():
try:
encoded_key = self.encode(wallet, key)
encoded_value = self.encode(wallet, value)
@@ -135,12 +133,12 @@ class LabelsPlugin(BasePlugin):
def start_wallet(self, wallet):
nonce = self.get_nonce(wallet)
self.print_error("wallet", wallet.basename(), "nonce is", nonce)
- mpk = wallet.get_fingerprint()
+ mpk = wallet.get_fingerprint().encode('ascii')
if not mpk:
return
- password = hashlib.sha1(mpk).digest().encode('hex')[:32]
+ password = hashlib.sha1(mpk).hexdigest()[:32].encode('ascii')
iv = hashlib.sha256(password).digest()[:16]
- wallet_id = hashlib.sha256(mpk).digest().encode('hex')
+ wallet_id = hashlib.sha256(mpk).hexdigest()
self.wallets[wallet] = (password, iv, wallet_id)
# If there is an auth token we can try to actually start syncing
t = threading.Thread(target=self.pull_thread, args=(wallet, False))
diff --git a/plugins/labels/qt.py b/plugins/labels/qt.py
@@ -9,7 +9,7 @@ from electrum_gui.qt import EnterButton
from electrum_gui.qt.util import ThreadedButton, Buttons
from electrum_gui.qt.util import WindowModalDialog, OkButton
-from labels import LabelsPlugin
+from .labels import LabelsPlugin
class Plugin(LabelsPlugin):
diff --git a/plugins/virtualkeyboard/qt.py b/plugins/virtualkeyboard/qt.py
@@ -3,8 +3,8 @@ from electrum.plugins import BasePlugin, hook
from electrum.i18n import _
import random
-class Plugin(BasePlugin):
+class Plugin(BasePlugin):
vkb = None
vkb_index = 0
@@ -25,7 +25,7 @@ class Plugin(BasePlugin):
self.vkb_index += 1
def virtual_keyboard(self, i, pw):
- i = i%3
+ i = i % 3
if i == 0:
chars = 'abcdefghijklmnopqrstuvwxyz '
elif i == 1:
@@ -35,9 +35,9 @@ class Plugin(BasePlugin):
n = len(chars)
s = []
- for i in xrange(n):
+ for i in range(n):
while True:
- k = random.randint(0,n-1)
+ k = random.randint(0, n - 1)
if k not in s:
s.append(k)
break
@@ -53,7 +53,7 @@ class Plugin(BasePlugin):
l_button.setFixedWidth(25)
l_button.setFixedHeight(25)
l_button.clicked.connect(add_target(chars[s[i]]))
- grid.addWidget(l_button, i/6, i%6)
+ grid.addWidget(l_button, i // 6, i % 6)
vbox.addLayout(grid)