def unfinished_confirm_password(self, run_next): vbox = QVBoxLayout() msg_label = WWLabel(_('Please enter wallet password before continue')) vbox.addWidget(msg_label) hbox = QHBoxLayout() pw_e = PasswordLineEdit('', self) pw_e.setFixedWidth(17 * char_width_in_lineedit()) pw_label = QLabel(_('Password') + ':') hbox.addWidget(pw_label) hbox.addWidget(pw_e) hbox.addStretch() vbox.addLayout(hbox) self.set_layout(vbox, title=_('Confirm wallet password')) try: while True: pw_e.setFocus() if self.loop.exec_() != 2: # 2 = next raise UserCancelled() password = pw_e.text() try: self.unfinished_check_password(password) break except InvalidPassword as e: self.show_message(title=_('Error'), msg=str(e)) continue except BaseException as e: self.logger.exception('') self.show_message(title=_('Error'), msg=repr(e)) raise UserCancelled() finally: pw_e.clear() return password
def run_user_interaction_loop(): while True: if self.loop.exec_() != 2: # 2 = next raise UserCancelled() assert temp_storage if temp_storage.file_exists( ) and not temp_storage.is_encrypted(): break if not temp_storage.file_exists(): break wallet_from_memory = get_wallet_from_daemon(temp_storage.path) if wallet_from_memory: raise WalletAlreadyOpenInMemory(wallet_from_memory) if temp_storage.file_exists() and temp_storage.is_encrypted(): if temp_storage.is_encrypted_with_user_pw(): password = pw_e.text() try: temp_storage.decrypt(password) break except InvalidPassword as e: self.show_message(title=_('Error'), msg=str(e)) continue except BaseException as e: self.logger.exception('') self.show_message(title=_('Error'), msg=repr(e)) raise UserCancelled() elif temp_storage.is_encrypted_with_hw_device(): try: self.run('choose_hw_device', HWD_SETUP_DECRYPT_WALLET, storage=temp_storage) except InvalidPassword as e: self.show_message( title=_('Error'), msg= _('Failed to decrypt using this hardware device.' ) + '\n' + _('If you use a passphrase, make sure it is correct.' )) self.reset_stack() return self.select_storage(path, get_wallet_from_daemon) except (UserCancelled, GoBack): raise except BaseException as e: self.logger.exception('') self.show_message(title=_('Error'), msg=repr(e)) raise UserCancelled() if temp_storage.is_past_initial_decryption(): break else: raise UserCancelled() else: raise Exception('Unexpected encryption version')
def check_device_dialog(self): match = re.search( r'v([0-9])+\.[0-9]+\.[0-9]+', run_in_hwd_thread(self.dbb_hid.get_serial_number_string)) if match is None: raise Exception("error detecting firmware version") major_version = int(match.group(1)) if major_version < MIN_MAJOR_VERSION: raise Exception( "Please upgrade to the newest firmware using the BitBox Desktop app: https://shiftcrypto.ch/start" ) # Set password if fresh device if self.password is None and not self.dbb_has_password(): if not self.setupRunning: return False # A fresh device cannot connect to an existing wallet msg = _("An uninitialized Digital Bitbox is detected.") + " " + \ _("Enter a new password below.") + "\n\n" + \ _("REMEMBER THE PASSWORD!") + "\n\n" + \ _("You cannot access your coins or a backup without the password.") + "\n" + \ _("A backup is saved automatically when generating a new wallet.") if self.password_dialog(msg): reply = self.hid_send_plain(b'{"password":"******"}') else: return False # Get password from user if not yet set msg = _("Enter your Digital Bitbox password:"******"led":"blink"}') if 'error' in reply: self.password = None if reply['error']['code'] == 109: msg = _("Incorrect password entered.") + "\n\n" + \ reply['error']['message'] + "\n\n" + \ _("Enter your Digital Bitbox password:"******"Unexpected error occurred.") + "\n\n" + \ reply['error']['message'] + "\n\n" + \ _("Enter your Digital Bitbox password:"******"device":"info"}') if reply['device']['id'] != "": self.recover_or_erase_dialog() # Already seeded else: self.seed_device_dialog() # Seed if not initialized self.mobile_pairing_dialog() return self.isInitialized
def callback_Failure(self, msg): # BaseClient's unfortunate call() implementation forces us to # raise exceptions on failure in order to unwind the stack. # However, making the user acknowledge they cancelled # gets old very quickly, so we suppress those. The NotInitialized # one is misnamed and indicates a passphrase request was cancelled. if msg.code in (self.types.FailureType.PinCancelled, self.types.FailureType.ActionCancelled, self.types.FailureType.NotInitialized): raise UserCancelled() raise RuntimeError(msg.message)
def __exit__(self, exc_type, e, traceback): self.end_flow() if e is not None: if isinstance(e, Cancelled): raise UserCancelled() from e elif isinstance(e, TrezorFailure): raise RuntimeError(str(e)) from e elif isinstance(e, OutdatedFirmwareError): raise OutdatedHwFirmwareException(e) from e else: return False return True
def get_seed(self): password = None if self.wallet.has_keystore_encryption(): password = self.password_dialog(parent=self.d.parent()) if not password: raise UserCancelled() keystore = self.wallet.get_keystore() if not keystore or not keystore.has_seed(): return self.extension = bool(keystore.get_passphrase(password)) return keystore.get_seed(password)
def f(method): import threading settings = self.request_trezor_init_settings(wizard, method, self.device) t = threading.Thread(target=self._initialize_device_safe, args=(settings, method, device_id, wizard, handler)) t.setDaemon(True) t.start() exit_code = wizard.loop.exec_() if exit_code != 0: # this method (initialize_device) was called with the expectation # of leaving the device in an initialized state when finishing. # signal that this is not the case: raise UserCancelled()
def exec_layout(self, layout, title=None, raise_on_cancel=True, next_enabled=True): self.set_layout(layout, title, next_enabled) result = self.loop.exec_() if not result and raise_on_cancel: raise UserCancelled() if result == 1: raise GoBack from None self.title.setVisible(False) self.back_button.setEnabled(False) self.next_button.setEnabled(False) self.main_widget.setVisible(False) self.please_wait.setVisible(True) self.refresh_gui() return result
def run_upgrades(self, storage: WalletStorage, db: 'WalletDB') -> None: path = storage.path if db.requires_split(): self.hide() msg = _( "The wallet '{}' contains multiple accounts, which are no longer supported since Firo Electrum 2.7.\n\n" "Do you want to split your wallet into multiple files?" ).format(path) if not self.question(msg): return file_list = db.split_accounts(path) msg = _('Your accounts have been moved to') + ':\n' + '\n'.join( file_list) + '\n\n' + _( 'Do you want to delete the old file') + ':\n' + path if self.question(msg): os.remove(path) self.show_warning(_('The file was removed')) # raise now, to avoid having the old storage opened raise UserCancelled() action = db.get_action() if action and db.requires_upgrade(): raise WalletFileException( 'Incomplete wallet files cannot be upgraded.') if action: self.hide() msg = _("The file '{}' contains an incompletely created wallet.\n" "Do you want to complete its creation now?").format(path) if not self.question(msg): if self.question( _("Do you want to delete '{}'?").format(path)): os.remove(path) self.show_warning(_('The file was removed')) return self.show() self.data = json.loads(storage.read()) self.run(action) for k, v in self.data.items(): db.put(k, v) db.write(storage) return if db.requires_upgrade(): self.upgrade_db(storage, db)
def sign_transaction(self, tx, password): if tx.is_complete(): return try: p2pkhTransaction = True inputhasharray = [] hasharray = [] pubkeyarray = [] # Build hasharray from inputs for i, txin in enumerate(tx.inputs()): if txin.is_coinbase_input(): self.give_error( "Coinbase not supported") # should never happen if txin.script_type != 'p2pkh': p2pkhTransaction = False my_pubkey, inputPath = self.find_my_pubkey_in_txinout(txin) if not inputPath: self.give_error("No matching pubkey for sign_transaction" ) # should never happen inputPath = convert_bip32_intpath_to_strpath(inputPath) inputHash = sha256d(bfh(tx.serialize_preimage(i))) hasharray_i = { 'hash': to_hexstr(inputHash), 'keypath': inputPath } hasharray.append(hasharray_i) inputhasharray.append(inputHash) # Build pubkeyarray from outputs for txout in tx.outputs(): assert txout.address if txout.is_change: changePubkey, changePath = self.find_my_pubkey_in_txinout( txout) assert changePath changePath = convert_bip32_intpath_to_strpath(changePath) changePubkey = changePubkey.hex() pubkeyarray_i = { 'pubkey': changePubkey, 'keypath': changePath } pubkeyarray.append(pubkeyarray_i) # Special serialization of the unsigned transaction for # the mobile verification app. # At the moment, verification only works for p2pkh transactions. if p2pkhTransaction: tx_copy = copy.deepcopy(tx) # monkey-patch method of tx_copy instance to change serialization def input_script(self, txin: PartialTxInput, *, estimate_size=False): if txin.script_type == 'p2pkh': return Transaction.get_preimage_script(txin) raise Exception("unsupported type %s" % txin.script_type) tx_copy.input_script = input_script.__get__( tx_copy, PartialTransaction) tx_dbb_serialized = tx_copy.serialize_to_network() else: # We only need this for the signing echo / verification. tx_dbb_serialized = None # Build sign command dbb_signatures = [] steps = math.ceil(1.0 * len(hasharray) / self.maxInputs) for step in range(int(steps)): hashes = hasharray[step * self.maxInputs:(step + 1) * self.maxInputs] msg = { "sign": { "data": hashes, "checkpub": pubkeyarray, }, } if tx_dbb_serialized is not None: msg["sign"]["meta"] = to_hexstr(sha256d(tx_dbb_serialized)) msg = json.dumps(msg).encode('ascii') dbb_client = self.plugin.get_client(self) if not dbb_client.is_paired(): raise Exception("Could not sign transaction.") reply = dbb_client.hid_send_encrypt(msg) if 'error' in reply: raise Exception(reply['error']['message']) if 'echo' not in reply: raise Exception("Could not sign transaction.") if self.plugin.is_mobile_paired( ) and tx_dbb_serialized is not None: reply['tx'] = tx_dbb_serialized self.plugin.comserver_post_notification(reply) if steps > 1: self.handler.show_message( _("Signing large transaction. Please be patient ...") + "\n\n" + _("To continue, touch the Digital Bitbox's blinking light for 3 seconds." ) + " " + _("(Touch {} of {})").format((step + 1), steps) + "\n\n" + _("To cancel, briefly touch the blinking light or wait for the timeout." ) + "\n\n") else: self.handler.show_message( _("Signing transaction...") + "\n\n" + _("To continue, touch the Digital Bitbox's blinking light for 3 seconds." ) + "\n\n" + _("To cancel, briefly touch the blinking light or wait for the timeout." )) # Send twice, first returns an echo for smart verification reply = dbb_client.hid_send_encrypt(msg) self.handler.finished() if 'error' in reply: if reply["error"].get('code') in (600, 601): # aborted via LED short touch or timeout raise UserCancelled() raise Exception(reply['error']['message']) if 'sign' not in reply: raise Exception("Could not sign transaction.") dbb_signatures.extend(reply['sign']) # Fill signatures if len(dbb_signatures) != len(tx.inputs()): raise Exception("Incorrect number of transactions signed." ) # Should never occur for i, txin in enumerate(tx.inputs()): for pubkey_bytes in txin.pubkeys: if txin.is_complete(): break signed = dbb_signatures[i] if 'recid' in signed: # firmware > v2.1.1 recid = int(signed['recid'], 16) s = binascii.unhexlify(signed['sig']) h = inputhasharray[i] pk = ecc.ECPubkey.from_sig_string(s, recid, h) pk = pk.get_public_key_hex(compressed=True) elif 'pubkey' in signed: # firmware <= v2.1.1 pk = signed['pubkey'] if pk != pubkey_bytes.hex(): continue sig_r = int(signed['sig'][:64], 16) sig_s = int(signed['sig'][64:], 16) sig = ecc.der_sig_from_r_and_s(sig_r, sig_s) sig = to_hexstr(sig) + '01' tx.add_signature_to_txin(txin_idx=i, signing_pubkey=pubkey_bytes.hex(), sig=sig) except UserCancelled: raise except BaseException as e: self.give_error(e, True) else: _logger.info(f"Transaction is_complete {tx.is_complete()}")