URI: 
       tqt/hww: temporarily bundle our own version of safetlib.qt.pinmatrix - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 7f3de8241c3856c2e873c5f6e9fa513f454e5d9b
   DIR parent e7d3fd32fbfc04d6b5b4bedadf1e4d1cf093b619
  HTML Author: SomberNight <somber.night@protonmail.com>
       Date:   Thu, 31 Jan 2019 20:58:04 +0100
       
       qt/hww: temporarily bundle our own version of safetlib.qt.pinmatrix
       
       until safetlib releases a new version that includes https://github.com/archos-safe-t/python-safet/commit/b1eab3dba4c04fdfc1fcf17b66662c28c5f2380e
       
       closes #4960
       
       Diffstat:
         M contrib/build-wine/deterministic.s… |       5 +++++
         M contrib/osx/osx.spec                |       5 +++++
         A electrum/plugins/safe_t/pinmatrix.… |     138 ++++++++++++++++++++++++++++++
         M electrum/plugins/safe_t/qt.py       |       5 ++++-
       
       4 files changed, 152 insertions(+), 1 deletion(-)
       ---
   DIR diff --git a/contrib/build-wine/deterministic.spec b/contrib/build-wine/deterministic.spec
       t@@ -23,6 +23,11 @@ hiddenimports += collect_submodules('keepkeylib')
        hiddenimports += collect_submodules('websocket')
        hiddenimports += collect_submodules('ckcc')
        
       +# safetlib imports PyQt5.Qt.  We use a local updated copy of pinmatrix.py until they
       +# release a new version that includes https://github.com/archos-safe-t/python-safet/commit/b1eab3dba4c04fdfc1fcf17b66662c28c5f2380e
       +hiddenimports.remove('safetlib.qt.pinmatrix')
       +
       +
        # Add libusb binary
        binaries = [(PYHOME+"/libusb-1.0.dll", ".")]
        
   DIR diff --git a/contrib/osx/osx.spec b/contrib/osx/osx.spec
       t@@ -66,6 +66,11 @@ hiddenimports += collect_submodules('keepkeylib')
        hiddenimports += collect_submodules('websocket')
        hiddenimports += collect_submodules('ckcc')
        
       +# safetlib imports PyQt5.Qt.  We use a local updated copy of pinmatrix.py until they
       +# release a new version that includes https://github.com/archos-safe-t/python-safet/commit/b1eab3dba4c04fdfc1fcf17b66662c28c5f2380e
       +hiddenimports.remove('safetlib.qt.pinmatrix')
       +
       +
        datas = [
            (electrum + PYPKG + '/*.json', PYPKG),
            (electrum + PYPKG + '/wordlist/english.txt', PYPKG + '/wordlist'),
   DIR diff --git a/electrum/plugins/safe_t/pinmatrix.py b/electrum/plugins/safe_t/pinmatrix.py
       t@@ -0,0 +1,138 @@
       +# copy of https://raw.githubusercontent.com/archos-safe-t/python-safet/b1eab3dba4c04fdfc1fcf17b66662c28c5f2380e/trezorlib/qt/pinmatrix.py
       +
       +from __future__ import print_function
       +import sys
       +import math
       +
       +try:
       +    from PyQt4.QtGui import (QPushButton, QLineEdit, QSizePolicy, QRegExpValidator, QLabel,
       +                             QApplication, QWidget, QGridLayout, QVBoxLayout, QHBoxLayout)
       +    from PyQt4.QtCore import QObject, SIGNAL, QRegExp, Qt, QT_VERSION_STR
       +except:
       +    from PyQt5.QtWidgets import (QPushButton, QLineEdit, QSizePolicy, QLabel,
       +                                 QApplication, QWidget, QGridLayout, QVBoxLayout, QHBoxLayout)
       +    from PyQt5.QtGui import QRegExpValidator
       +    from PyQt5.QtCore import QRegExp, Qt, QT_VERSION_STR
       +
       +
       +class PinButton(QPushButton):
       +    def __init__(self, password, encoded_value):
       +        super(PinButton, self).__init__('?')
       +        self.password = password
       +        self.encoded_value = encoded_value
       +
       +        if QT_VERSION_STR >= '5':
       +            self.clicked.connect(self._pressed)
       +        elif QT_VERSION_STR >= '4':
       +            QObject.connect(self, SIGNAL('clicked()'), self._pressed)
       +        else:
       +            raise RuntimeError('Unsupported Qt version')
       +
       +    def _pressed(self):
       +        self.password.setText(self.password.text() + str(self.encoded_value))
       +        self.password.setFocus()
       +
       +
       +class PinMatrixWidget(QWidget):
       +    '''
       +        Displays widget with nine blank buttons and password box.
       +        Encodes button clicks into sequence of numbers for passing
       +        into PinAck messages of TREZOR.
       +
       +        show_strength=True may be useful for entering new PIN
       +    '''
       +    def __init__(self, show_strength=True, parent=None):
       +        super(PinMatrixWidget, self).__init__(parent)
       +
       +        self.password = QLineEdit()
       +        self.password.setValidator(QRegExpValidator(QRegExp('[1-9]+'), None))
       +        self.password.setEchoMode(QLineEdit.Password)
       +
       +        if QT_VERSION_STR >= '5':
       +            self.password.textChanged.connect(self._password_changed)
       +        elif QT_VERSION_STR >= '4':
       +            QObject.connect(self.password, SIGNAL('textChanged(QString)'), self._password_changed)
       +        else:
       +            raise RuntimeError('Unsupported Qt version')
       +
       +        self.strength = QLabel()
       +        self.strength.setMinimumWidth(75)
       +        self.strength.setAlignment(Qt.AlignCenter)
       +        self._set_strength(0)
       +
       +        grid = QGridLayout()
       +        grid.setSpacing(0)
       +        for y in range(3)[::-1]:
       +            for x in range(3):
       +                button = PinButton(self.password, x + y * 3 + 1)
       +                button.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
       +                button.setFocusPolicy(Qt.NoFocus)
       +                grid.addWidget(button, 3 - y, x)
       +
       +        hbox = QHBoxLayout()
       +        hbox.addWidget(self.password)
       +        if show_strength:
       +            hbox.addWidget(self.strength)
       +
       +        vbox = QVBoxLayout()
       +        vbox.addLayout(grid)
       +        vbox.addLayout(hbox)
       +        self.setLayout(vbox)
       +
       +    def _set_strength(self, strength):
       +        if strength < 3000:
       +            self.strength.setText('weak')
       +            self.strength.setStyleSheet("QLabel { color : #d00; }")
       +        elif strength < 60000:
       +            self.strength.setText('fine')
       +            self.strength.setStyleSheet("QLabel { color : #db0; }")
       +        elif strength < 360000:
       +            self.strength.setText('strong')
       +            self.strength.setStyleSheet("QLabel { color : #0a0; }")
       +        else:
       +            self.strength.setText('ULTIMATE')
       +            self.strength.setStyleSheet("QLabel { color : #000; font-weight: bold;}")
       +
       +    def _password_changed(self, password):
       +        self._set_strength(self.get_strength())
       +
       +    def get_strength(self):
       +        digits = len(set(str(self.password.text())))
       +        strength = math.factorial(9) / math.factorial(9 - digits)
       +        return strength
       +
       +    def get_value(self):
       +        return self.password.text()
       +
       +
       +if __name__ == '__main__':
       +    '''
       +        Demo application showing PinMatrix widget in action
       +    '''
       +    app = QApplication(sys.argv)
       +
       +    matrix = PinMatrixWidget()
       +
       +    def clicked():
       +        print("PinMatrix value is", matrix.get_value())
       +        print("Possible button combinations:", matrix.get_strength())
       +        sys.exit()
       +
       +    ok = QPushButton('OK')
       +    if QT_VERSION_STR >= '5':
       +        ok.clicked.connect(clicked)
       +    elif QT_VERSION_STR >= '4':
       +        QObject.connect(ok, SIGNAL('clicked()'), clicked)
       +    else:
       +        raise RuntimeError('Unsupported Qt version')
       +
       +    vbox = QVBoxLayout()
       +    vbox.addWidget(matrix)
       +    vbox.addWidget(ok)
       +
       +    w = QWidget()
       +    w.setLayout(vbox)
       +    w.move(100, 100)
       +    w.show()
       +
       +    app.exec_()
   DIR diff --git a/electrum/plugins/safe_t/qt.py b/electrum/plugins/safe_t/qt.py
       t@@ -174,7 +174,10 @@ class Plugin(SafeTPlugin, QtPlugin):
        
            @classmethod
            def pin_matrix_widget_class(self):
       -        from safetlib.qt.pinmatrix import PinMatrixWidget
       +        # We use a local updated copy of pinmatrix.py until safetlib
       +        # releases a new version that includes https://github.com/archos-safe-t/python-safet/commit/b1eab3dba4c04fdfc1fcf17b66662c28c5f2380e
       +        # from safetlib.qt.pinmatrix import PinMatrixWidget
       +        from .pinmatrix import PinMatrixWidget
                return PinMatrixWidget