mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-08-27 15:31:31 +00:00
Trezor: Matrix recovery support
New Trezor firmware has matrix recovery support, which is a new recovery method that doesn't leak the entered words.
This commit is contained in:
parent
034b0a0313
commit
6dd5161729
2 changed files with 95 additions and 0 deletions
|
@ -84,6 +84,15 @@ class GuiMixin(object):
|
|||
return self.proto.PassphraseStateAck()
|
||||
|
||||
def callback_WordRequest(self, msg):
|
||||
if (msg.type is not None
|
||||
and msg.type in (self.types.WordRequestType_Matrix9,
|
||||
self.types.WordRequestType_Matrix6)):
|
||||
num = 9 if msg.type == self.types.WordRequestType_Matrix9 else 6
|
||||
char = self.handler.get_matrix(num)
|
||||
if (char == 'x'):
|
||||
return self.proto.Cancel()
|
||||
return self.proto.WordAck(word=char)
|
||||
|
||||
self.step += 1
|
||||
msg = _("Step {}/24. Enter seed word as explained on "
|
||||
"your {}:").format(self.step, self.device)
|
||||
|
|
|
@ -30,16 +30,86 @@ PASSPHRASE_NOT_PIN = _(
|
|||
"If you forget a passphrase you will be unable to access any "
|
||||
"bitcoins in the wallet behind it. A passphrase is not a PIN. "
|
||||
"Only change this if you are sure you understand it.")
|
||||
MATRIX_RECOVERY = (
|
||||
"Enter the recovery words by pressing the buttons according to what "
|
||||
"the device shows on its display. You can also use your NUMPAD.\n"
|
||||
"Press BACKSPACE to go back a choice or word.\n")
|
||||
|
||||
|
||||
class MatrixDialog(WindowModalDialog):
|
||||
|
||||
def __init__(self, parent):
|
||||
super(MatrixDialog, self).__init__(parent)
|
||||
self.setWindowTitle(_("Trezor Matrix Recovery"))
|
||||
self.num = 9
|
||||
self.loop = QEventLoop()
|
||||
|
||||
vbox = QVBoxLayout(self)
|
||||
vbox.addWidget(WWLabel(MATRIX_RECOVERY))
|
||||
|
||||
grid = QGridLayout()
|
||||
grid.setSpacing(0)
|
||||
self.char_buttons = [];
|
||||
for y in range(3):
|
||||
for x in range(3):
|
||||
button = QPushButton('?')
|
||||
button.clicked.connect(partial(self.process_key, ord('1') + y * 3 + x))
|
||||
grid.addWidget(button, 3 - y, x)
|
||||
self.char_buttons.append(button)
|
||||
vbox.addLayout(grid)
|
||||
|
||||
hbox = QHBoxLayout()
|
||||
self.backspace_button = QPushButton(_("<="))
|
||||
self.backspace_button.clicked.connect(partial(self.process_key, Qt.Key_Backspace))
|
||||
self.cancel_button = QPushButton(_("Cancel"))
|
||||
self.cancel_button.clicked.connect(partial(self.process_key, Qt.Key_Escape))
|
||||
buttons = Buttons(self.backspace_button, self.cancel_button)
|
||||
vbox.addSpacing(40)
|
||||
vbox.addLayout(buttons)
|
||||
self.refresh()
|
||||
self.show()
|
||||
|
||||
def refresh(self):
|
||||
for y in range(3):
|
||||
self.char_buttons[3 * y + 1].setEnabled(self.num == 9)
|
||||
|
||||
def is_valid(self, key):
|
||||
return key >= ord('1') and key <= ord('9')
|
||||
|
||||
def process_key(self, key):
|
||||
self.data = None
|
||||
if key == Qt.Key_Backspace:
|
||||
self.data = '\010'
|
||||
elif key == Qt.Key_Escape:
|
||||
self.data = 'x'
|
||||
elif self.is_valid(key):
|
||||
self.char_buttons[key - ord('1')].setFocus()
|
||||
self.data = '%c' % key;
|
||||
if self.data:
|
||||
self.loop.exit(0)
|
||||
|
||||
def keyPressEvent(self, event):
|
||||
self.process_key(event.key())
|
||||
if not self.data:
|
||||
QDialog.keyPressEvent(self, event)
|
||||
|
||||
def get_matrix(self, num):
|
||||
self.num = num
|
||||
self.refresh()
|
||||
self.loop.exec_()
|
||||
|
||||
|
||||
class QtHandler(QtHandlerBase):
|
||||
|
||||
pin_signal = pyqtSignal(object)
|
||||
matrix_signal = pyqtSignal(object)
|
||||
|
||||
def __init__(self, win, pin_matrix_widget_class, device):
|
||||
super(QtHandler, self).__init__(win, device)
|
||||
self.pin_signal.connect(self.pin_dialog)
|
||||
self.pin_matrix_widget_class = pin_matrix_widget_class
|
||||
self.matrix_signal.connect(self.matrix_recovery_dialog)
|
||||
self.matrix_dialog = None
|
||||
|
||||
def get_pin(self, msg):
|
||||
self.done.clear()
|
||||
|
@ -47,6 +117,16 @@ class QtHandler(QtHandlerBase):
|
|||
self.done.wait()
|
||||
return self.response
|
||||
|
||||
def get_matrix(self, msg):
|
||||
self.done.clear()
|
||||
self.matrix_signal.emit(msg)
|
||||
self.done.wait()
|
||||
data = self.matrix_dialog.data
|
||||
if data == 'x':
|
||||
self.matrix_dialog.accept()
|
||||
self.matrix_dialog = None
|
||||
return data
|
||||
|
||||
def pin_dialog(self, msg):
|
||||
# Needed e.g. when resetting a device
|
||||
self.clear_dialog()
|
||||
|
@ -61,6 +141,12 @@ class QtHandler(QtHandlerBase):
|
|||
self.response = str(matrix.get_value())
|
||||
self.done.set()
|
||||
|
||||
def matrix_recovery_dialog(self, msg):
|
||||
if not self.matrix_dialog:
|
||||
self.matrix_dialog = MatrixDialog(self.top_level_window())
|
||||
self.matrix_dialog.get_matrix(msg)
|
||||
self.done.set()
|
||||
|
||||
|
||||
class QtPlugin(QtPluginBase):
|
||||
# Derived classes must provide the following class-static variables:
|
||||
|
|
Loading…
Add table
Reference in a new issue