py3 in qtgui

This commit is contained in:
Dmitry Sorokin 2017-01-30 12:36:56 +03:00 committed by ThomasV
parent 5be78950ca
commit d304ccdf17
28 changed files with 246 additions and 323 deletions

View File

@ -48,11 +48,11 @@ if jnius:
threading.Thread.run = thread_check_run
# monkeypatch unicode constructor for py3
if six.PY3:
import builtins
builtins.unicode = str
builtins.QString = str
builtins.long = int
# if six.PY3:
# import builtins
# builtins.unicode = str
# builtins.QString = str
# builtins.long = int
script_dir = os.path.dirname(os.path.realpath(__file__))
is_bundle = getattr(sys, 'frozen', False)

View File

@ -48,7 +48,7 @@ class AddressList(MyTreeWidget):
def on_update(self):
self.wallet = self.parent.wallet
item = self.currentItem()
current_address = item.data(0, Qt.UserRole).toString() if item else None
current_address = item.data(0, Qt.UserRole) if item else None
self.clear()
receiving_addresses = self.wallet.get_receiving_addresses()
change_addresses = self.wallet.get_change_addresses()
@ -97,7 +97,7 @@ class AddressList(MyTreeWidget):
can_delete = self.wallet.can_delete_address()
selected = self.selectedItems()
multi_select = len(selected) > 1
addrs = [unicode(item.text(0)) for item in selected]
addrs = [item.text(0) for item in selected]
if not addrs:
return
if not multi_select:

View File

@ -37,7 +37,7 @@ class AmountEdit(MyLineEdit):
return 8
def numbify(self):
text = unicode(self.text()).strip()
text = self.text().strip()
if text == '!':
self.shortcut.emit()
return

View File

@ -76,7 +76,7 @@ class Console(QtGui.QPlainTextEdit):
def getCommand(self):
doc = self.document()
curr_line = unicode(doc.findBlockByLineNumber(doc.lineCount() - 1).text())
curr_line = doc.findBlockByLineNumber(doc.lineCount() - 1).text()
curr_line = curr_line.rstrip()
curr_line = curr_line[len(self.prompt):]
return curr_line
@ -86,7 +86,7 @@ class Console(QtGui.QPlainTextEdit):
return
doc = self.document()
curr_line = unicode(doc.findBlockByLineNumber(doc.lineCount() - 1).text())
curr_line = doc.findBlockByLineNumber(doc.lineCount() - 1).text()
self.moveCursor(QtGui.QTextCursor.End)
for i in range(len(curr_line) - len(self.prompt)):
self.moveCursor(QtGui.QTextCursor.Left, QtGui.QTextCursor.KeepAnchor)
@ -95,7 +95,6 @@ class Console(QtGui.QPlainTextEdit):
self.textCursor().insertText(command)
self.moveCursor(QtGui.QTextCursor.End)
def show_completions(self, completions):
if self.completions_visible:
self.hide_completions()
@ -113,7 +112,6 @@ class Console(QtGui.QPlainTextEdit):
self.moveCursor(QtGui.QTextCursor.End)
self.completions_visible = True
def hide_completions(self):
if not self.completions_visible:
return
@ -125,7 +123,6 @@ class Console(QtGui.QPlainTextEdit):
self.moveCursor(QtGui.QTextCursor.End)
self.completions_visible = False
def getConstruct(self, command):
if self.construct:
prev_command = self.construct[-1]

View File

@ -55,7 +55,7 @@ class ContactList(MyTreeWidget):
def on_edited(self, item, column, prior):
if column == 0: # Remove old contact if renamed
self.parent.contacts.pop(prior)
self.parent.set_contact(unicode(item.text(0)), unicode(item.text(1)))
self.parent.set_contact(item.text(0), item.text(1))
def import_contacts(self):
wallet_folder = self.parent.get_wallet_folder()
@ -72,11 +72,11 @@ class ContactList(MyTreeWidget):
menu.addAction(_("New contact"), lambda: self.parent.new_contact_dialog())
menu.addAction(_("Import file"), lambda: self.parent.import_contacts())
else:
names = [unicode(item.text(0)) for item in selected]
keys = [unicode(item.text(1)) for item in selected]
names = [item.text(0) for item in selected]
keys = [item.text(1) for item in selected]
column = self.currentColumn()
column_title = self.headerItem().text(column)
column_data = '\n'.join([unicode(item.text(column)) for item in selected])
column_data = '\n'.join([item.text(column) for item in selected])
menu.addAction(_("Copy %s")%column_title, lambda: self.parent.app.clipboard().setText(column_data))
if column in self.editable_columns:
menu.addAction(_("Edit %s")%column_title, lambda: self.editItem(item, column))
@ -91,7 +91,7 @@ class ContactList(MyTreeWidget):
def on_update(self):
item = self.currentItem()
current_key = item.data(0, Qt.UserRole).toString() if item else None
current_key = item.data(0, Qt.UserRole) if item else None
self.clear()
for key in sorted(self.parent.contacts.keys()):
_type, name = self.parent.contacts[key]

View File

@ -77,7 +77,7 @@ class HistoryList(MyTreeWidget):
self.wallet = self.parent.wallet
h = self.wallet.get_history(self.get_domain())
item = self.currentItem()
current_tx = item.data(0, Qt.UserRole).toString() if item else None
current_tx = item.data(0, Qt.UserRole) if item else None
self.clear()
fx = self.parent.fx
if fx: fx.history_used_spot = False
@ -128,7 +128,7 @@ class HistoryList(MyTreeWidget):
child_count = root.childCount()
for i in range(child_count):
item = root.child(i)
txid = str(item.data(0, Qt.UserRole).toString())
txid = item.data(0, Qt.UserRole)
label = self.wallet.get_label(txid)
item.setText(3, label)
@ -147,7 +147,7 @@ class HistoryList(MyTreeWidget):
if not item:
return
column = self.currentColumn()
tx_hash = str(item.data(0, Qt.UserRole).toString())
tx_hash = item.data(0, Qt.UserRole)
if not tx_hash:
return
if column is 0:

View File

@ -444,8 +444,8 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
@wizard_dialog
def choice_dialog(self, title, message, choices, run_next):
c_values = map(lambda x: x[0], choices)
c_titles = map(lambda x: x[1], choices)
c_values = [x[0] for x in choices]
c_titles = [x[1] for x in choices]
clayout = ChoicesLayout(message, c_titles)
vbox = QVBoxLayout()
vbox.addLayout(clayout.layout())
@ -473,7 +473,7 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
vbox.addWidget(line)
vbox.addWidget(WWLabel(warning))
self.exec_layout(vbox, title, next_enabled=test(default))
return ' '.join(unicode(line.text()).split())
return ' '.join(line.text().split())
@wizard_dialog
def show_xpub_dialog(self, xpub, run_next):

View File

@ -73,8 +73,10 @@ class InvoiceList(MyTreeWidget):
def create_menu(self, position):
menu = QMenu()
item = self.itemAt(position)
key = str(item.data(0, 32).toString())
column = self.currentColumn()
if not item:
return
key = item.data(0, 32)
column = self.currentColumn()
column_title = self.headerItem().text(column)
column_data = item.text(column)
pr = self.parent.invoices.get(key)

View File

@ -384,7 +384,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
def open_wallet(self):
wallet_folder = self.get_wallet_folder()
filename = unicode(QFileDialog.getOpenFileName(self, "Select your wallet file", wallet_folder))
filename = QFileDialog.getOpenFileName(self, "Select your wallet file", wallet_folder)
if not filename:
return
self.gui_object.new_window(filename)
@ -393,7 +393,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
def backup_wallet(self):
path = self.wallet.storage.path
wallet_folder = os.path.dirname(path)
filename = unicode( QFileDialog.getSaveFileName(self, _('Enter a filename for the copy of your wallet'), wallet_folder) )
filename = QFileDialog.getSaveFileName(self, _('Enter a filename for the copy of your wallet'), wallet_folder)
if not filename:
return
@ -578,16 +578,16 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
# custom wrappers for getOpenFileName and getSaveFileName, that remember the path selected by the user
def getOpenFileName(self, title, filter = ""):
directory = self.config.get('io_dir', unicode(os.path.expanduser('~')))
fileName = unicode( QFileDialog.getOpenFileName(self, title, directory, filter) )
directory = self.config.get('io_dir', os.path.expanduser('~'))
fileName = QFileDialog.getOpenFileName(self, title, directory, filter)
if fileName and directory != os.path.dirname(fileName):
self.config.set_key('io_dir', os.path.dirname(fileName), True)
return fileName
def getSaveFileName(self, title, filename, filter = ""):
directory = self.config.get('io_dir', unicode(os.path.expanduser('~')))
directory = self.config.get('io_dir', os.path.expanduser('~'))
path = os.path.join( directory, filename )
fileName = unicode( QFileDialog.getSaveFileName(self, title, path, filter) )
fileName = QFileDialog.getSaveFileName(self, title, path, filter)
if fileName and directory != os.path.dirname(fileName):
self.config.set_key('io_dir', os.path.dirname(fileName), True)
return fileName
@ -880,7 +880,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
def save_payment_request(self):
addr = str(self.receive_address_e.text())
amount = self.receive_amount_e.get_amount()
message = unicode(self.receive_message_e.text())
message = self.receive_message_e.text()
if not message and not amount:
self.show_error(_('No message or amount'))
return False
@ -982,7 +982,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
def update_receive_qr(self):
addr = str(self.receive_address_e.text())
amount = self.receive_amount_e.get_amount()
message = unicode(self.receive_message_e.text()).encode('utf8')
message = self.receive_message_e.text()
self.save_request_button.setEnabled((amount is not None) or (message != ""))
uri = util.create_URI(addr, amount, message)
self.receive_qr.setData(uri)
@ -1281,7 +1281,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
if self.payment_request and self.payment_request.has_expired():
self.show_error(_('Payment request has expired'))
return
label = unicode( self.message_e.text() )
label = self.message_e.text()
if self.payment_request:
outputs = self.payment_request.get_outputs()
@ -1513,7 +1513,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
if not URI:
return
try:
out = util.parse_URI(unicode(URI), self.on_pr)
out = util.parse_URI(URI, self.on_pr)
except BaseException as e:
self.show_error(_('Invalid bitcoin URI:') + '\n' + str(e))
return
@ -1807,7 +1807,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
vbox.addLayout(grid)
vbox.addLayout(Buttons(CancelButton(d), OkButton(d)))
if d.exec_():
self.set_contact(unicode(line2.text()), str(line1.text()))
self.set_contact(line2.text(), line1.text())
def show_master_public_keys(self):
dialog = WindowModalDialog(self, "Master Public Keys")
@ -1848,7 +1848,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
except BaseException as e:
self.show_error(str(e))
return
from seed_dialog import SeedDialog
from .seed_dialog import SeedDialog
d = SeedDialog(self, seed, passphrase)
d.exec_()
@ -1889,7 +1889,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
@protected
def do_sign(self, address, message, signature, password):
address = str(address.text()).strip()
message = unicode(message.toPlainText()).encode('utf-8').strip()
message = message.toPlainText().strip()
if not bitcoin.is_address(address):
self.show_message('Invalid Bitcoin address.')
return
@ -1906,7 +1906,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
def do_verify(self, address, message, signature):
address = str(address.text()).strip()
message = unicode(message.toPlainText()).encode('utf-8').strip()
message = message.toPlainText().strip()
if not bitcoin.is_address(address):
self.show_message('Invalid Bitcoin address.')
return
@ -1970,10 +1970,10 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
self.wallet.thread.add(task, on_success=message_e.setText)
def do_encrypt(self, message_e, pubkey_e, encrypted_e):
message = unicode(message_e.toPlainText())
message = message_e.toPlainText()
message = message.encode('utf-8')
try:
encrypted = bitcoin.encrypt_message(message, str(pubkey_e.text()))
encrypted = bitcoin.encrypt_message(message, pubkey_e.text())
encrypted_e.setText(encrypted)
except BaseException as e:
traceback.print_exc(file=sys.stdout)
@ -2386,7 +2386,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
lang_label = HelpLabel(_('Language') + ':', lang_help)
lang_combo = QComboBox()
from electrum.i18n import languages
lang_combo.addItems(languages.values())
lang_combo.addItems(list(languages.values()))
try:
index = languages.keys().index(self.config.get("language",''))
except Exception:
@ -2570,7 +2570,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
msg = _("Install the zbar package to enable this.")
qr_label = HelpLabel(_('Video Device') + ':', msg)
qr_combo.setEnabled(qrscanner.libzbar is not None)
on_video_device = lambda x: self.config.set_key("video_device", str(qr_combo.itemData(x).toString()), True)
on_video_device = lambda x: self.config.set_key("video_device", qr_combo.itemData(x), True)
qr_combo.currentIndexChanged.connect(on_video_device)
gui_widgets.append((qr_label, qr_combo))

View File

@ -386,7 +386,7 @@ class NetworkChoiceLayout(object):
def change_protocol(self, use_ssl):
p = 's' if use_ssl else 't'
host = unicode(self.server_host.text())
host = self.server_host.text()
pp = self.servers.get(host, DEFAULT_PORTS)
if p not in pp.keys():
p = pp.keys()[0]

View File

@ -44,7 +44,7 @@ def check_password_strength(password):
:param password: password entered by user in New Password
:return: password strength Weak or Medium or Strong
'''
password = unicode(password)
password = password
n = math.log(len(set(password)))
num = re.search("[0-9]", password) is not None and re.match("^[0-9]*$", password) is None
caps = password != password.upper() and password != password.lower()
@ -156,11 +156,11 @@ class PasswordLayout(object):
def old_password(self):
if self.kind == PW_CHANGE:
return unicode(self.pw.text()) or None
return self.pw.text() or None
return None
def new_password(self):
pw = unicode(self.new_pw.text())
pw = self.new_pw.text()
# Empty passphrases are fine and returned empty.
if pw == "" and self.kind != PW_PASSPHRASE:
pw = None

View File

@ -120,7 +120,7 @@ class PayToEdit(ScanQRTextEdit):
if self.is_pr:
return
# filter out empty lines
lines = filter(lambda x: x, self.lines())
lines = [i for i in self.lines() if i]
outputs = []
total = 0
self.payto_address = None
@ -180,7 +180,7 @@ class PayToEdit(ScanQRTextEdit):
return self.outputs[:]
def lines(self):
return unicode(self.toPlainText()).split('\n')
return self.toPlainText().split('\n')
def is_multiline(self):
return len(self.lines()) > 1
@ -242,14 +242,14 @@ class PayToEdit(ScanQRTextEdit):
QPlainTextEdit.keyPressEvent(self, e)
ctrlOrShift = e.modifiers() and (Qt.ControlModifier or Qt.ShiftModifier)
if self.c is None or (ctrlOrShift and e.text().isEmpty()):
if self.c is None or (ctrlOrShift and not e.text()):
return
eow = QString("~!@#$%^&*()_+{}|:\"<>?,./;'[]\\-=")
hasModifier = (e.modifiers() != Qt.NoModifier) and not ctrlOrShift;
eow = "~!@#$%^&*()_+{}|:\"<>?,./;'[]\\-="
hasModifier = (e.modifiers() != Qt.NoModifier) and not ctrlOrShift
completionPrefix = self.textUnderCursor()
if hasModifier or e.text().isEmpty() or completionPrefix.length() < 1 or eow.contains(e.text().right(1)):
if hasModifier or not e.text() or completionPrefix.length() < 1 or eow.contains(e.text().right(1)):
self.c.popup().hide()
return

View File

@ -22,11 +22,11 @@ class ShowQRTextEdit(ButtonsTextEdit):
run_hook('show_text_edit', self)
def qr_show(self):
from qrcodewidget import QRDialog
from .qrcodewidget import QRDialog
try:
s = str(self.toPlainText())
except:
s = unicode(self.toPlainText())
s = self.toPlainText()
QRDialog(s).exec_()
def contextMenuEvent(self, e):
@ -45,7 +45,7 @@ class ScanQRTextEdit(ButtonsTextEdit, MessageBoxMixin):
run_hook('scan_text_edit', self)
def file_input(self):
fileName = unicode(QFileDialog.getOpenFileName(self, 'select file'))
fileName = QFileDialog.getOpenFileName(self, 'select file')
if not fileName:
return
with open(fileName, "r") as f:

View File

@ -52,7 +52,6 @@ def seed_warning_msg(seed):
]) % len(seed.split())
class SeedLayout(QVBoxLayout):
#options
is_bip39 = False
@ -92,7 +91,6 @@ class SeedLayout(QVBoxLayout):
self.is_ext = cb_ext.isChecked() if 'ext' in self.options else False
self.is_bip39 = cb_bip39.isChecked() if 'bip39' in self.options else False
def __init__(self, seed=None, title=None, icon=True, msg=None, options=None, is_seed=None, passphrase=None, parent=None):
QVBoxLayout.__init__(self)
self.parent = parent
@ -140,7 +138,7 @@ class SeedLayout(QVBoxLayout):
self.addWidget(self.seed_warning)
def get_seed(self):
text = unicode(self.seed_e.text())
text = self.seed_e.text()
return ' '.join(text.split())
def on_edit(self):
@ -159,7 +157,6 @@ class SeedLayout(QVBoxLayout):
self.parent.next_button.setEnabled(b)
class KeysLayout(QVBoxLayout):
def __init__(self, parent=None, title=None, is_valid=None):
QVBoxLayout.__init__(self)
@ -171,7 +168,7 @@ class KeysLayout(QVBoxLayout):
self.addWidget(self.text_e)
def get_text(self):
return unicode(self.text_e.text())
return self.text_e.text()
def on_edit(self):
b = self.is_valid(self.get_text())

View File

@ -260,7 +260,7 @@ def line_dialog(parent, title, label, ok_label, default=None):
l.addWidget(txt)
l.addLayout(Buttons(CancelButton(dialog), OkButton(dialog, ok_label)))
if dialog.exec_():
return unicode(txt.text())
return txt.text()
def text_dialog(parent, title, label, ok_label, default=None):
from qrtextedit import ScanQRTextEdit
@ -275,7 +275,7 @@ def text_dialog(parent, title, label, ok_label, default=None):
l.addWidget(txt)
l.addLayout(Buttons(CancelButton(dialog), OkButton(dialog, ok_label)))
if dialog.exec_():
return unicode(txt.toPlainText())
return txt.toPlainText()
class ChoicesLayout(object):
def __init__(self, msg, choices, on_clicked=None, checked_index=0):
@ -341,15 +341,15 @@ def filename_field(parent, config, defaultname, select_msg):
hbox = QHBoxLayout()
directory = config.get('io_dir', unicode(os.path.expanduser('~')))
directory = config.get('io_dir', os.path.expanduser('~'))
path = os.path.join( directory, defaultname )
filename_e = QLineEdit()
filename_e.setText(path)
def func():
text = unicode(filename_e.text())
text = filename_e.text()
_filter = "*.csv" if text.endswith(".csv") else "*.json" if text.endswith(".json") else None
p = unicode( QFileDialog.getSaveFileName(None, select_msg, text, _filter))
p = QFileDialog.getSaveFileName(None, select_msg, text, _filter)
if p:
filename_e.setText(p)
@ -360,7 +360,7 @@ def filename_field(parent, config, defaultname, select_msg):
vbox.addLayout(hbox)
def set_csv(v):
text = unicode(filename_e.text())
text = filename_e.text()
text = text.replace(".json",".csv") if v else text.replace(".csv",".json")
filename_e.setText(text)
@ -409,7 +409,7 @@ class MyTreeWidget(QTreeWidget):
def editItem(self, item, column):
if column in self.editable_columns:
self.editing_itemcol = (item, column, unicode(item.text(column)))
self.editing_itemcol = (item, column, item.text(column))
# Calling setFlags causes on_changed events for some reason
item.setFlags(item.flags() | Qt.ItemIsEditable)
QTreeWidget.editItem(self, item, column)
@ -471,7 +471,7 @@ class MyTreeWidget(QTreeWidget):
def on_edited(self, item, column, prior):
'''Called only when the text actually changes'''
key = str(item.data(0, Qt.UserRole).toString())
text = unicode(item.text(column))
text = item.text(column)
self.parent.wallet.set_label(key, text)
self.parent.history_list.update_labels()
self.parent.update_completions()
@ -501,10 +501,10 @@ class MyTreeWidget(QTreeWidget):
def filter(self, p):
columns = self.__class__.filter_columns
p = unicode(p).lower()
p = p.lower()
self.current_filter = p
for item in self.get_leaves(self.invisibleRootItem()):
item.setHidden(all([unicode(item.text(column)).lower().find(p) == -1
item.setHidden(all([item.text(column).lower().find(p) == -1
for column in columns]))

View File

@ -63,7 +63,7 @@ class UTXOList(MyTreeWidget):
self.addChild(utxo_item)
def create_menu(self, position):
selected = [str(x.data(0, Qt.UserRole).toString()) for x in self.selectedItems()]
selected = [x.data(0, Qt.UserRole) for x in self.selectedItems()]
if not selected:
return
menu = QMenu()

View File

@ -28,10 +28,11 @@ import hashlib
import base64
import re
import hmac
import os
from lib.util import bfh, bh2u
from . import version
from .util import print_error, InvalidPassword, assert_bytes, _bytes, to_bytes
from .util import print_error, InvalidPassword, assert_bytes, to_bytes
import ecdsa
import pyaes
@ -206,12 +207,12 @@ def op_push(i):
def sha256(x):
x = to_bytes(x, 'utf8')
return _bytes(hashlib.sha256(x).digest())
return bytes(hashlib.sha256(x).digest())
def Hash(x):
x = to_bytes(x, 'utf8')
out = _bytes(sha256(sha256(x)))
out = bytes(sha256(sha256(x)))
return out
@ -363,7 +364,7 @@ def base_decode(v, length, base):
chars = __b43chars
long_value = 0
for (i, c) in enumerate(v[::-1]):
long_value += chars.find(_bytes([c])) * (base**i)
long_value += chars.find(bytes([c])) * (base**i)
result = bytearray()
while long_value >= 256:
div, mod = divmod(long_value, 256)

View File

@ -243,8 +243,8 @@ class Commands:
tx = Transaction(tx)
if privkey:
pubkey = bitcoin.public_key_from_private_key(privkey)
h160 = bitcoin.hash_160(pubkey.decode('hex'))
x_pubkey = 'fd' + (chr(0) + h160).encode('hex')
h160 = bitcoin.hash_160(bfh(pubkey))
x_pubkey = 'fd' + bh2u(b'\x00' + h160)
tx.sign({x_pubkey:privkey})
else:
self.wallet.sign_transaction(tx, password)
@ -266,8 +266,8 @@ class Commands:
def createmultisig(self, num, pubkeys):
"""Create multisig address"""
assert isinstance(pubkeys, list), (type(num), type(pubkeys))
redeem_script = transaction.multisig_script(pubkeys, num)
address = bitcoin.hash160_to_p2sh(hash_160(redeem_script.decode('hex')))
redeem_script = Transaction.multisig_script(pubkeys, num)
address = bitcoin.hash160_to_p2sh(hash_160(bfh(redeem_script)))
return {'address':address, 'redeemScript':redeem_script}
@command('w')

View File

@ -33,8 +33,9 @@ import os
import sys
import time
# import jsonrpclib
# from jsonrpclib.SimpleJSONRPCServer import SimpleJSONRPCServer, SimpleJSONRPCRequestHandler
# from jsonrpc import JSONRPCResponseManager
import jsonrpclib
from jsonrpclib.SimpleJSONRPCServer import SimpleJSONRPCServer, SimpleJSONRPCRequestHandler
from .version import ELECTRUM_VERSION
from .network import Network
@ -47,12 +48,15 @@ from .simple_config import SimpleConfig
from .plugins import run_hook
from .exchange_rate import FxThread
def get_lockfile(config):
return os.path.join(config.path, 'daemon')
def remove_lockfile(lockfile):
os.unlink(lockfile)
def get_fd_or_server(config):
'''Tries to create the lockfile, using O_EXCL to
prevent races. If it succeeds it returns the FD.
@ -71,6 +75,7 @@ def get_fd_or_server(config):
# Couldn't connect; remove lockfile and try again.
remove_lockfile(lockfile)
def get_server(config):
lockfile = get_lockfile(config)
while True:
@ -82,7 +87,8 @@ def get_server(config):
# Test daemon is running
server.ping()
return server
except:
except Exception as e:
print_error(e)
pass
if not create_time or create_time < time.time() - 1.0:
return None
@ -90,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):
@ -129,12 +135,12 @@ class Daemon(DaemonThread):
try:
server = SimpleJSONRPCServer((host, port), logRequests=False,
requestHandler=RequestHandler)
except:
self.print_error('Warning: cannot initialize RPC server on host', host)
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, repr((server.socket.getsockname(), time.time())))
os.write(fd, bytes(repr((server.socket.getsockname(), time.time())), 'utf8'))
os.close(fd)
server.timeout = 0.1
for cmdname in known_commands:

View File

@ -290,7 +290,7 @@ class LocalBitcoins(ExchangeBase):
class MercadoBitcoin(ExchangeBase):
def get_rates(self, ccy):
json = self.get_json('api.bitvalor.com', '/v1/ticker.json')
json = self.get_json('api.bitvalor.com', '/v1/ticker.json')
return {'BRL': Decimal(json['ticker_1h']['exchanges']['MBT']['last'])}

View File

@ -38,6 +38,9 @@ import time
import traceback
import requests
from lib import print_error
ca_path = requests.certs.where()
from . import util
@ -60,6 +63,7 @@ def Connection(server, queue, config_path):
c.start()
return c
class TcpConnection(threading.Thread, util.PrintError):
def __init__(self, server, queue, config_path):
@ -131,8 +135,9 @@ class TcpConnection(threading.Thread, util.PrintError):
return
# try with CA first
try:
s = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_SSLv23, cert_reqs=ssl.CERT_REQUIRED, ca_certs=ca_path, do_handshake_on_connect=True)
s = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1_1, cert_reqs=ssl.CERT_REQUIRED, ca_certs=ca_path, do_handshake_on_connect=True)
except ssl.SSLError as e:
print_error(e)
s = None
if s and self.check_host_name(s.getpeercert(), self.host):
self.print_error("SSL certificate signed by CA")
@ -143,7 +148,7 @@ class TcpConnection(threading.Thread, util.PrintError):
if s is None:
return
try:
s = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_SSLv23, cert_reqs=ssl.CERT_NONE, ca_certs=None)
s = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1_1, cert_reqs=ssl.CERT_NONE, ca_certs=None)
except ssl.SSLError as e:
self.print_error("SSL error retrieving SSL certificate:", e)
return
@ -166,9 +171,9 @@ class TcpConnection(threading.Thread, util.PrintError):
if self.use_ssl:
try:
s = ssl.wrap_socket(s,
ssl_version=ssl.PROTOCOL_SSLv23,
ssl_version=ssl.PROTOCOL_TLSv1_1,
cert_reqs=ssl.CERT_REQUIRED,
ca_certs= (temporary_path if is_new else cert_path),
ca_certs=(temporary_path if is_new else cert_path),
do_handshake_on_connect=True)
except ssl.SSLError as e:
self.print_error("SSL error:", e)
@ -196,11 +201,11 @@ class TcpConnection(threading.Thread, util.PrintError):
os.unlink(cert_path)
return
self.print_error("wrong certificate")
if e.errno == 104:
return
return
except BaseException as e:
self.print_error(e)
if e.errno == 104:
return
traceback.print_exc(file=sys.stderr)
return
@ -216,6 +221,7 @@ class TcpConnection(threading.Thread, util.PrintError):
self.print_error("connected")
self.queue.put((self.server, socket))
class Interface(util.PrintError):
"""The Interface class handles a socket connected to a single remote
electrum server. It's exposed API is:
@ -274,7 +280,7 @@ class Interface(util.PrintError):
n = self.num_requests()
wire_requests = self.unsent_requests[0:n]
try:
self.pipe.send_all(map(make_dict, wire_requests))
self.pipe.send_all([make_dict(*r) for r in wire_requests])
except socket.error as e:
self.print_error("socket error:", e)
return False
@ -368,13 +374,13 @@ def _match_hostname(name, val):
return val.startswith('*.') and name.endswith(val[1:])
def test_certificates():
from .simple_config import SimpleConfig
config = SimpleConfig()
mydir = os.path.join(config.path, "certs")
certs = os.listdir(mydir)
for c in certs:
print(c)
p = os.path.join(mydir,c)
with open(p) as f:
cert = f.read()

View File

@ -103,7 +103,7 @@ SERVER_RETRY_INTERVAL = 10
def parse_servers(result):
""" parse servers list into dict format"""
from version import PROTOCOL_VERSION
from .version import PROTOCOL_VERSION
servers = {}
for item in result:
host = item[1]
@ -123,7 +123,8 @@ def parse_servers(result):
if pruning_level == '': pruning_level = '0'
try:
is_recent = cmp(util.normalize_version(version), util.normalize_version(PROTOCOL_VERSION)) >= 0
except Exception:
except Exception as e:
print_error(e)
is_recent = False
if out and is_recent:
@ -152,13 +153,15 @@ from .simple_config import SimpleConfig
proxy_modes = ['socks4', 'socks5', 'http']
def serialize_proxy(p):
if type(p) != dict:
if not isinstance(p, dict):
return None
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]:
if not isinstance(s, str):
return None
if s.lower() == 'none':
return None
@ -183,15 +186,18 @@ def deserialize_proxy(s):
proxy["password"] = args[n]
return proxy
def deserialize_server(server_str):
host, port, protocol = str(server_str).split(':')
assert protocol in 'st'
int(port) # Throw if cannot be converted to int
return host, port, protocol
def serialize_server(host, port, protocol):
return str(':'.join([host, port, protocol]))
class Network(util.DaemonThread):
"""The Network class manages a set of connections to remote electrum
servers, each connected socket is handled by an Interface() object.
@ -209,7 +215,7 @@ class Network(util.DaemonThread):
if config is None:
config = {} # Do not use mutables as default values!
util.DaemonThread.__init__(self)
self.config = SimpleConfig(config) if type(config) == type({}) else config
self.config = SimpleConfig(config) if isinstance(config, dict) else config
self.num_server = 10 if not self.config.get('oneserver') else 0
self.blockchains = blockchain.read_blockchains(self.config)
self.print_error("blockchains", self.blockchains.keys())
@ -390,7 +396,7 @@ class Network(util.DaemonThread):
def get_interfaces(self):
'''The interfaces that are in connected state'''
return self.interfaces.keys()
return list(self.interfaces.keys())
def get_servers(self):
if self.irc_servers:
@ -456,7 +462,7 @@ class Network(util.DaemonThread):
def stop_network(self):
self.print_error("stopping network")
for interface in self.interfaces.values():
for interface in list(self.interfaces.values()):
self.close_interface(interface)
if self.interface:
self.close_interface(self.interface)
@ -596,7 +602,7 @@ class Network(util.DaemonThread):
def get_index(self, method, params):
""" hashable index for subscriptions and cache"""
return str(method) + (':' + str(params[0]) if params else '')
return str(method) + (':' + str(params[0]) if params else '')
def process_responses(self, interface):
responses = interface.get_responses()
@ -647,6 +653,7 @@ class Network(util.DaemonThread):
def send(self, messages, callback):
'''Messages is a list of (method, params) tuples'''
messages = list(messages)
with self.lock:
self.pending_sends.append((messages, callback))
@ -730,7 +737,8 @@ class Network(util.DaemonThread):
self.connection_down(server)
# Send pings and shut down stale interfaces
for interface in self.interfaces.values():
# must use copy of values
for interface in list(self.interfaces.values()):
if interface.has_timed_out():
self.connection_down(interface.server)
elif interface.ping_required():
@ -1059,15 +1067,14 @@ class Network(util.DaemonThread):
host, port, protocol = server.split(':')
self.set_parameters(host, port, protocol, proxy, auto_connect)
def get_local_height(self):
return self.blockchain().height()
def synchronous_get(self, request, timeout=30):
queue = queue.Queue()
self.send([request], queue.put)
q = queue.Queue()
self.send([request], q.put)
try:
r = queue.get(True, timeout)
r = q.get(True, timeout)
except queue.Empty:
raise BaseException('Server did not answer')
if r.get('error'):

View File

@ -51,7 +51,7 @@ except ImportError:
from . import bitcoin
from . import util
from .util import print_error
from .util import print_error, bh2u, bfh
from . import transaction
from . import x509
from . import rsakey
@ -126,7 +126,7 @@ class PaymentRequest:
def parse(self, r):
if self.error:
return
self.id = bitcoin.sha256(r)[0:16].encode('hex')
self.id = bh2u(bitcoin.sha256(r)[0:16])
try:
self.data = pb2.PaymentRequest()
self.data.ParseFromString(r)
@ -321,7 +321,7 @@ def make_unsigned_request(req):
if amount is None:
amount = 0
memo = req['memo']
script = Transaction.pay_script(TYPE_ADDRESS, addr).decode('hex')
script = bfh(Transaction.pay_script(TYPE_ADDRESS, addr))
outputs = [(script, amount)]
pd = pb2.PaymentDetails()
for script, amount in outputs:
@ -445,7 +445,7 @@ def serialize_request(req):
signature = req.get('sig')
requestor = req.get('name')
if requestor and signature:
pr.signature = signature.decode('hex')
pr.signature = bfh(signature)
pr.pki_type = 'dnssec+btc'
pr.pki_data = str(requestor)
return pr
@ -477,7 +477,7 @@ class InvoiceStore(object):
def load(self, d):
for k, v in d.items():
try:
pr = PaymentRequest(v.get('hex').decode('hex'))
pr = bfh(PaymentRequest(v.get('hex')))
pr.tx = v.get('txid')
pr.requestor = v.get('requestor')
self.invoices[k] = pr
@ -499,7 +499,7 @@ class InvoiceStore(object):
l = {}
for k, pr in self.invoices.items():
l[k] = {
'hex': str(pr).encode('hex'),
'hex': bh2u(pr),
'requestor': pr.requestor,
'txid': pr.tx
}

View File

@ -33,7 +33,7 @@ import hashlib
from .bitcoin import Hash, hash_encode
from .transaction import Transaction
from .util import print_error, print_msg, ThreadJob
from .util import print_error, print_msg, ThreadJob, bh2u
class Synchronizer(ThreadJob):
@ -89,7 +89,7 @@ class Synchronizer(ThreadJob):
status = ''
for tx_hash, height in h:
status += tx_hash + ':%d:' % height
return hashlib.sha256(status).digest().encode('hex')
return bh2u(hashlib.sha256(status.encode('ascii')).digest())
def addr_subscription_response(self, response):
params, result = self.parse_response(response)
@ -114,7 +114,7 @@ class Synchronizer(ThreadJob):
self.print_error("receiving history", addr, len(result))
server_status = self.requested_histories[addr]
hashes = set(map(lambda item: item['tx_hash'], result))
hist = map(lambda item: (item['tx_hash'], item['height']), result)
hist = list(map(lambda item: (item['tx_hash'], item['height']), result))
# tx_fees
tx_fees = [(item['tx_hash'], item.get('fee')) for item in result]
tx_fees = dict(filter(lambda x:x[1] is not None, tx_fees))
@ -140,7 +140,7 @@ class Synchronizer(ThreadJob):
if not params:
return
tx_hash, tx_height = params
#assert tx_hash == hash_encode(Hash(result.decode('hex')))
#assert tx_hash == hash_encode(Hash(bytes.fromhex(result)))
tx = Transaction(result)
try:
tx.deserialize()

View File

@ -170,9 +170,9 @@ class Enumeration:
for x in enumList:
if isinstance(x, tuple):
x, i = x
if not isinstance(x, six.text_type):
if not isinstance(x, str):
raise EnumException("enum name is not a string: " + x)
if not isinstance(i, six.integer_types):
if not isinstance(i, int):
raise EnumException("enum value is not an integer: " + i)
if x in uniqueNames:
raise EnumException("enum name is not unique: " + x)
@ -715,9 +715,9 @@ class Transaction:
txin = inputs[i]
# TODO: py3 hex
if self.is_segwit_input(txin):
hashPrevouts = Hash(''.join(self.serialize_outpoint(txin) for txin in inputs).decode('hex')).encode('hex')
hashSequence = Hash(''.join(int_to_hex(txin.get('sequence', 0xffffffff - 1), 4) for txin in inputs).decode('hex')).encode('hex')
hashOutputs = Hash(''.join(self.serialize_output(o) for o in outputs).decode('hex')).encode('hex')
hashPrevouts = bh2u(Hash(bfh(''.join(self.serialize_outpoint(txin) for txin in inputs))))
hashSequence = bh2u(Hash(bfh(''.join(int_to_hex(txin.get('sequence', 0xffffffff - 1), 4) for txin in inputs))))
hashOutputs = bh2u(Hash(bfh(''.join(self.serialize_output(o) for o in outputs))))
outpoint = self.serialize_outpoint(txin)
preimage_script = self.get_preimage_script(txin)
scriptCode = var_int(len(preimage_script)/2) + preimage_script

View File

@ -141,7 +141,7 @@ class DaemonThread(threading.Thread, PrintError):
for job in self.jobs:
try:
job.run()
except:
except Exception as e:
traceback.print_exc(file=sys.stderr)
def remove_jobs(self, jobs):
@ -170,7 +170,8 @@ class DaemonThread(threading.Thread, PrintError):
self.print_error("stopped")
is_verbose = False
# TODO: disable
is_verbose = True
def set_verbosity(b):
global is_verbose
is_verbose = b
@ -281,63 +282,8 @@ def assert_str(*args):
assert isinstance(x, six.string_types)
def __str(x, encoding='utf8'):
if six.PY3:
return x.decode(encoding)
def _bytes(x=None, encoding=None, **kw):
"""
py2-py3 aware wrapper to "bytes()" like constructor
:param x:
:return:
"""
if encoding is not None:
kw['encoding'] = encoding
if x is None:
x = []
if six.PY3:
if isinstance(x, bytes):
return x
return bytes(x, **kw)
else:
return bytearray(x, **kw)
def _to_bytes2(x, enc):
if isinstance(x, bytearray):
return bytearray(x)
if isinstance(x, six.text_type):
return bytearray(x.encode(enc))
elif isinstance(x, six.binary_type):
return bytearray(x)
else:
raise TypeError("Not a string or bytes like object")
def _to_bytes3(x, enc):
if isinstance(x, bytes):
return x
if isinstance(x, str):
return x.encode(enc)
elif isinstance(x, bytearray):
return bytes(x)
else:
raise TypeError("Not a string or bytes like object")
def _to_string2(x, enc):
if isinstance(x, (str, bytes)):
return x
if isinstance(x, unicode):
return x.encode(enc)
if isinstance(x, bytearray):
return x.decode(enc)
else:
raise TypeError("Not a string or bytes like object")
def _to_string3(x, enc):
def to_string(x, enc):
if isinstance(x, (bytes, bytearray)):
return x.decode(enc)
if isinstance(x, str):
@ -349,35 +295,16 @@ def to_bytes(something, encoding='utf8'):
"""
cast string to bytes() like object, but for python2 support it's bytearray copy
"""
raise NotImplementedError("This call should be redefined")
if isinstance(something, bytes):
return something
if isinstance(something, str):
return something.encode(encoding)
elif isinstance(something, bytearray):
return bytes(something)
else:
raise TypeError("Not a string or bytes like object")
def to_bytes(something, encoding='utf8'):
"""
cast string to str object
"""
raise NotImplementedError("This call should be redefined")
if six.PY3:
to_bytes = _to_bytes3
to_string = _to_string3
else:
to_bytes = _to_bytes2
to_string = _to_string2
if six.PY3:
bfh_builder = lambda x: bytes.fromhex(x)
else:
bfh_builder = lambda x: x.decode('hex') # str(bytearray.fromhex(x))
# def ufh(x):
# """
# py2-py3 aware wrapper for str.decode('hex')
# :param x: str
# :return: str
# """
# if
# return binascii.unhexlify(x)
bfh_builder = lambda x: bytes.fromhex(x)
def hfu(x):
@ -700,20 +627,18 @@ else:
builtins.input = raw_input
def parse_json(message):
n = message.find('\n')
# TODO: check \r\n pattern
n = message.find(b'\n')
if n==-1:
return None, message
try:
j = json.loads( message[0:n] )
j = json.loads(message[0:n].decode('utf8'))
except:
j = None
return j, message[n+1:]
class timeout(Exception):
pass
@ -723,11 +648,11 @@ import json
import ssl
import time
class SocketPipe:
class SocketPipe:
def __init__(self, socket):
self.socket = socket
self.message = ''
self.message = b''
self.set_timeout(0.1)
self.recv_time = time.time()
@ -757,10 +682,10 @@ class SocketPipe:
raise timeout
else:
print_error("pipe: socket error", err)
data = ''
data = b''
except:
traceback.print_exc(file=sys.stderr)
data = ''
data = b''
if not data: # Connection closed remotely
return None
@ -769,10 +694,12 @@ class SocketPipe:
def send(self, request):
out = json.dumps(request) + '\n'
out = out.encode('utf8')
self._send(out)
def send_all(self, requests):
out = ''.join(map(lambda x: json.dumps(x) + '\n', requests))
print(requests)
out = b''.join(map(lambda x: (json.dumps(x) + '\n').encode('utf8'), requests))
self._send(out)
def _send(self, out):
@ -798,7 +725,6 @@ class SocketPipe:
raise e
class QueuePipe:
def __init__(self, send_queue=None, get_queue=None):
@ -833,9 +759,8 @@ class QueuePipe:
self.send(request)
def check_www_dir(rdir):
import urllib, urlparse, shutil, os
import urllib, shutil, os
if not os.path.exists(rdir):
os.mkdir(rdir)
index = os.path.join(rdir, 'index.html')
@ -850,7 +775,7 @@ def check_www_dir(rdir):
"https://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css"
]
for URL in files:
path = urlparse.urlsplit(URL).path
path = urllib_parse.urlsplit(URL).path
filename = os.path.basename(path)
path = os.path.join(rdir, filename)
if not os.path.exists(path):

View File

@ -51,7 +51,7 @@ from .version import *
from .keystore import load_keystore, Hardware_KeyStore
from .storage import multisig_type
import transaction
from . import transaction
from .transaction import Transaction
from .plugins import run_hook
from . import bitcoin
@ -297,6 +297,7 @@ class Abstract_Wallet(PrintError):
self.verifier.merkle_roots.pop(tx_hash, None)
# tx will be verified only if height > 0
print('unverif', tx_hash, tx_height)
if tx_hash not in self.verified_tx:
self.unverified_tx[tx_hash] = tx_height
@ -759,7 +760,7 @@ class Abstract_Wallet(PrintError):
return ''
def get_tx_status(self, tx_hash, height, conf, timestamp):
from util import format_time
from .util import format_time
if conf == 0:
tx = self.transactions.get(tx_hash)
if not tx:
@ -1417,16 +1418,11 @@ class Imported_Wallet(Abstract_Wallet):
def add_input_sig_info(self, txin, address):
addrtype, hash160 = bc_address_to_hash_160(address)
if six.PY3:
x_pubkey = 'fd' + bh2u(bytes([addrtype]) + hash160)
else:
x_pubkey = 'fd' + bh2u(chr(addrtype) + hash160)
x_pubkey = 'fd' + bh2u(bytes([addrtype]) + hash160)
txin['x_pubkeys'] = [x_pubkey]
txin['signatures'] = [None]
class Deterministic_Wallet(Abstract_Wallet):
def __init__(self, storage):
@ -1508,7 +1504,7 @@ class Deterministic_Wallet(Abstract_Wallet):
if len(addresses) < limit:
self.create_new_address(for_change)
continue
if map(lambda a: self.address_is_old(a), addresses[-limit:] ) == limit*[False]:
if list(map(lambda a: self.address_is_old(a), addresses[-limit:] )) == limit*[False]:
break
else:
self.create_new_address(for_change)
@ -1521,7 +1517,7 @@ class Deterministic_Wallet(Abstract_Wallet):
else:
if len(self.receiving_addresses) != len(self.keystore.keypairs):
pubkeys = self.keystore.keypairs.keys()
self.receiving_addresses = map(self.pubkeys_to_address, pubkeys)
self.receiving_addresses = [self.pubkeys_to_address(i) for i in pubkeys]
self.save_addresses()
for addr in self.receiving_addresses:
self.add_address(addr)
@ -1652,7 +1648,7 @@ class P2SH:
def pubkeys_to_address(self, pubkey):
redeem_script = self.pubkeys_to_redeem_script(pubkey)
return bitcoin.hash160_to_p2sh(hash_160(redeem_script.decode('hex')))
return bitcoin.hash160_to_p2sh(hash_160(bfh(redeem_script)))
class Standard_Wallet(Simple_Deterministic_Wallet):
@ -1664,17 +1660,14 @@ class Standard_Wallet(Simple_Deterministic_Wallet):
def pubkeys_to_address(self, pubkey):
if not self.is_segwit:
return bitcoin.public_key_to_p2pkh(pubkey.decode('hex'))
return bitcoin.public_key_to_p2pkh(bfh(pubkey))
elif bitcoin.TESTNET:
redeem_script = self.pubkeys_to_redeem_script(pubkey)
return bitcoin.hash160_to_p2sh(hash_160(redeem_script.decode('hex')))
return bitcoin.hash160_to_p2sh(hash_160(bfh(redeem_script)))
else:
raise NotImplementedError()
class Multisig_Wallet(Deterministic_Wallet, P2SH):
# generic m of n
gap_limit = 20

View File

@ -31,7 +31,7 @@ import six
from datetime import datetime
import sys
from . import util
from .util import profiler, print_error
from .util import profiler, print_error, bh2u
import ecdsa
import hashlib
@ -74,7 +74,7 @@ class CertificateError(Exception):
# helper functions
def bitstr_to_bytestr(s):
if s[0] != '\x00':
if s[0] != 0x00:
raise BaseException('no padding')
return s[1:]
@ -83,14 +83,13 @@ def bytestr_to_int(s):
i = 0
for char in s:
i <<= 8
i |= ord(char)
i |= char
return i
def decode_OID(s):
s = map(ord, s)
r = []
r.append(s[0] / 40)
r.append(s[0] // 40)
r.append(s[0] % 40)
k = 0
for i in s[1:]:
@ -103,7 +102,7 @@ def decode_OID(s):
def encode_OID(oid):
x = map(int, oid.split('.'))
x = [int(i) for i in oid.split('.')]
s = chr(x[0] * 40 + x[1])
for i in x[2:]:
ss = chr(i % 128)
@ -114,11 +113,11 @@ def encode_OID(oid):
return s
class ASN1_Node(str):
class ASN1_Node(bytes):
def get_node(self, ix):
# return index of first byte, first content byte and last byte.
first = ord(self[ix + 1])
if (ord(self[ix + 1]) & 0x80) == 0:
first = self[ix + 1]
if (self[ix + 1] & 0x80) == 0:
length = first
ixf = ix + 2
ixl = ixf + length - 1
@ -129,72 +128,62 @@ class ASN1_Node(str):
ixl = ixf + length - 1
return ix, ixf, ixl
def root(self):
return self.get_node(0)
def root(self):
return self.get_node(0)
def next_node(self, node):
ixs, ixf, ixl = node
return self.get_node(ixl + 1)
def first_child(self, node):
ixs, ixf, ixl = node
if self[ixs] & 0x20 != 0x20:
raise BaseException('Can only open constructed types.', hex(self[ixs]))
return self.get_node(ixf)
def next_node(self, node):
ixs, ixf, ixl = node
return self.get_node(ixl + 1)
def is_child_of(node1, node2):
ixs, ixf, ixl = node1
jxs, jxf, jxl = node2
return ((ixf <= jxs) and (jxl <= ixl)) or ((jxf <= ixs) and (ixl <= jxl))
def get_all(self, node):
# return type + length + value
ixs, ixf, ixl = node
return self[ixs:ixl + 1]
def first_child(self, node):
ixs, ixf, ixl = node
if ord(self[ixs]) & 0x20 != 0x20:
raise BaseException('Can only open constructed types.', hex(ord(self[ixs])))
return self.get_node(ixf)
def get_value_of_type(self, node, asn1_type):
# 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]))
return self[ixf:ixl + 1]
def get_value(self, node):
ixs, ixf, ixl = node
return self[ixf:ixl + 1]
def is_child_of(node1, node2):
ixs, ixf, ixl = node1
jxs, jxf, jxl = node2
return ((ixf <= jxs) and (jxl <= ixl)) or ((jxf <= ixs) and (ixl <= jxl))
def get_all(self, node):
# return type + length + value
ixs, ixf, ixl = node
return self[ixs:ixl + 1]
def get_value_of_type(self, node, asn1_type):
# verify type byte and return content
ixs, ixf, ixl = node
if ASN1_TYPES[asn1_type] != ord(self[ixs]):
raise BaseException('Wrong type:', hex(ord(self[ixs])), hex(ASN1_TYPES[asn1_type]))
return self[ixf:ixl + 1]
def get_value(self, node):
ixs, ixf, ixl = node
return self[ixf:ixl + 1]
def get_children(self, node):
nodes = []
ii = self.first_child(node)
nodes.append(ii)
while ii[2] < node[2]:
ii = self.next_node(ii)
def get_children(self, node):
nodes = []
ii = self.first_child(node)
nodes.append(ii)
return nodes
while ii[2] < node[2]:
ii = self.next_node(ii)
nodes.append(ii)
return nodes
def get_sequence(self):
return list(map(lambda j: self.get_value(j), self.get_children(self.root())))
def get_sequence(self):
return map(lambda j: self.get_value(j), self.get_children(self.root()))
def get_dict(self, node):
p = {}
for ii in self.get_children(node):
for iii in self.get_children(ii):
iiii = self.first_child(iii)
oid = decode_OID(self.get_value_of_type(iiii, 'OBJECT IDENTIFIER'))
iiii = self.next_node(iiii)
value = self.get_value(iiii)
p[oid] = value
return p
def get_dict(self, node):
p = {}
for ii in self.get_children(node):
for iii in self.get_children(ii):
iiii = self.first_child(iii)
oid = decode_OID(self.get_value_of_type(iiii, 'OBJECT IDENTIFIER'))
iiii = self.next_node(iiii)
value = self.get_value(iiii)
p[oid] = value
return p
class X509(object):
@ -202,14 +191,14 @@ class X509(object):
self.bytes = bytearray(b)
der = ASN1_Node(str(b))
der = ASN1_Node(b)
root = der.root()
cert = der.first_child(root)
# data for signature
self.data = der.get_all(cert)
# optional version field
if der.get_value(cert)[0] == chr(0xa0):
if der.get_value(cert)[0] == 0xa0:
version = der.first_child(cert)
serial_number = der.next_node(version)
else:
@ -269,10 +258,10 @@ class X509(object):
# Subject Key Identifier
r = value.root()
value = value.get_value_of_type(r, 'OCTET STRING')
self.SKI = value.encode('hex')
self.SKI = bh2u(value)
elif oid == '2.5.29.35':
# Authority Key Identifier
self.AKI = value.get_sequence()[0].encode('hex')
self.AKI = bh2u(value.get_sequence()[0])
else:
pass
@ -303,8 +292,8 @@ class X509(object):
import time
now = time.time()
TIMESTAMP_FMT = '%y%m%d%H%M%SZ'
not_before = time.mktime(time.strptime(self.notBefore, TIMESTAMP_FMT))
not_after = time.mktime(time.strptime(self.notAfter, TIMESTAMP_FMT))
not_before = time.mktime(time.strptime(self.notBefore.decode('ascii'), TIMESTAMP_FMT))
not_after = time.mktime(time.strptime(self.notAfter.decode('ascii'), TIMESTAMP_FMT))
if not_before > now:
raise CertificateError('Certificate has not entered its valid date range. (%s)' % self.get_common_name())
if not_after <= now:
@ -320,7 +309,7 @@ def load_certificates(ca_path):
ca_list = {}
ca_keyID = {}
with open(ca_path, 'rb') as f:
s = f.read().decode('utf8')
s = f.read().decode('ascii')
bList = pem.dePemList(s, "CERTIFICATE")
for b in bList:
try: