def __init__(self, parent, config): QDialog.__init__(self, parent=parent) Ui_ConfigDlg.__init__(self) WndUtils.__init__(self, config) self.config = config self.main_window = parent self.local_config = AppConfig() self.local_config.copy_from(config) # list of connections from self.local_config.dash_net_configs split on separate lists for mainnet and testnet self.connections_mainnet = [] self.connections_testnet = [] self.connections_current = None self.current_network_cfg: Optional[DashNetworkConnectionCfg] = None # block ui controls -> cur config data copying while setting ui controls initial values self.disable_cfg_update = False self.is_modified = False self.setupUi()
def get_owner_key_to_display(self) -> str: ret = '' if self.masternode: if self.edit_mode: if self.masternode.dmn_owner_key_type == InputKeyType.PRIVATE: ret = self.masternode.dmn_owner_private_key else: ret = self.masternode.dmn_owner_address else: try: if self.masternode.dmn_owner_key_type == InputKeyType.PRIVATE: if self.act_view_as_owner_private_key.isChecked(): ret = self.masternode.dmn_owner_private_key elif self.act_view_as_owner_public_address.isChecked(): if self.masternode.dmn_owner_private_key: ret = crown_utils.wif_privkey_to_address(self.masternode.dmn_owner_private_key, self.app_config.crown_network) elif self.act_view_as_owner_public_key.isChecked(): if self.masternode.dmn_owner_private_key: ret = crown_utils.wif_privkey_to_pubkey(self.masternode.dmn_owner_private_key) elif self.act_view_as_owner_public_key_hash.isChecked(): if self.masternode.dmn_owner_private_key: pubkey = crown_utils.wif_privkey_to_pubkey(self.masternode.dmn_owner_private_key) pubkey_bin = bytes.fromhex(pubkey) pub_hash = bitcoin.bin_hash160(pubkey_bin) ret = pub_hash.hex() else: ret = '???' else: if self.act_view_as_owner_public_address.isChecked(): ret = self.masternode.dmn_owner_address elif self.act_view_as_owner_public_key_hash.isChecked(): ret = self.masternode.get_dmn_owner_pubkey_hash() else: ret = '???' except Exception as e: msg = str(e) if not msg: msg = 'Key conversion error.' WndUtils.errorMsg(msg) return ret
def validate_firmware_internal(self, version, fw, expected_fingerprint=None): """Adapted version of the 'validate_firmware' function from trezorlib""" if version == trezorlib.firmware.FirmwareFormat.TREZOR_ONE: if fw.embedded_onev2: log.debug( "Trezor One firmware with embedded v2 image (1.8.0 or later)" ) else: log.debug("Trezor One firmware image.") elif version == trezorlib.firmware.FirmwareFormat.TREZOR_ONE_V2: log.debug("Trezor One v2 firmware (1.8.0 or later)") elif version == trezorlib.firmware.FirmwareFormat.TREZOR_T: log.debug("Trezor T firmware image.") vendor = fw.vendor_header.text vendor_version = "{major}.{minor}".format( **fw.vendor_header.version) log.debug("Vendor header from {}, version {}".format( vendor, vendor_version)) try: trezorlib.firmware.validate(version, fw, allow_unsigned=False) log.debug("Signatures are valid.") except trezorlib.firmware.Unsigned: if WndUtils.query_dlg( 'No signatures found. Continue?', buttons=QMessageBox.Yes | QMessageBox.No, default_button=QMessageBox.Yes, icon=QMessageBox.Information) == QMessageBox.No: raise CancelException() try: trezorlib.firmware.validate(version, fw, allow_unsigned=True) log.debug("Unsigned firmware looking OK.") except trezorlib.firmware.FirmwareIntegrityError as e: log.exception(e) raise Exception("Firmware validation failed, aborting.") except trezorlib.firmware.FirmwareIntegrityError as e: log.exception(e) raise Exception("Firmware validation failed, aborting.") fingerprint = trezorlib.firmware.digest(version, fw).hex() log.debug("Firmware fingerprint: {}".format(fingerprint)) if version == trezorlib.firmware.FirmwareFormat.TREZOR_ONE and fw.embedded_onev2: fingerprint_onev2 = trezorlib.firmware.digest( trezorlib.firmware.FirmwareFormat.TREZOR_ONE_V2, fw.embedded_onev2).hex() log.debug( "Embedded v2 image fingerprint: {}".format(fingerprint_onev2)) if expected_fingerprint and fingerprint != expected_fingerprint: log.error("Expected fingerprint: {}".format(expected_fingerprint)) raise Exception("Fingerprints do not match, aborting.")
def __init__(self, parent: QDialog, config: AppConfig, dashd_intf: DashdInterface, raw_transaction: str, decoded_transaction: Optional[dict] = None, dependent_transactions: Optional[dict] = None ): QDialog.__init__(self, parent=parent) Ui_TransactionDlg.__init__(self) WndUtils.__init__(self, config) self.config = config self.parent = parent self.dashd_intf = dashd_intf self.transaction_sent = False self.raw_transaction = raw_transaction self.tx_id = None # will be decoded from rawtransaction self.tx_size = None # as above self.decoded_transaction: Optional[dict] = decoded_transaction self.dependent_transactions = dependent_transactions # key: txid, value: transaction dict self.setupUi()
def load_device_by_mnemonic(hw_type: HWType, hw_device_id: Optional[str], mnemonic_words: str, pin: str, passphrase_enbled: bool, hw_label: str, passphrase: str, secondary_pin: str, parent_window = None) -> Tuple[Optional[str], bool]: """ Initializes hardware wallet with a mnemonic words. For security reasons use this function only on an offline system, that will never be connected to the Internet. :param hw_type: app_config.HWType :param hw_device_id: id of the device selected by the user (TrezorClient, KeepkeyClient); None for Ledger Nano S :param mnemonic_words: string of 12/18/24 mnemonic words (separeted by spaces) :param pin: string with a new pin :param passphrase_enbled: if True, hw will have passphrase enabled (Trezor/Keepkey) :param hw_label: label for device (Trezor/Keepkey) :param passphrase: passphrase to be saved in the device (Ledger Nano S) :param secondary_pin: PIN securing passphrase (Ledger Nano S) :param parent_window: ref to a window according to which will be centered message dialogs created here :return: Tuple Ret[0]: Device id. If a device is wiped before initializing with mnemonics, a new device id is generated. It's returned to the caller. Ret[1]: True, if the user cancelled the operation. In this situation we deliberately don't raise the 'cancelled' exception, because in the case of changing of the device id (when wiping) we want to pass it back to the caller. Ret[0] and Ret[1] are None for Ledger devices. """ def load(ctrl, hw_device_id: str, mnemonic: str, pin: str, passphrase_enbled: bool, hw_label: str) -> \ Tuple[Optional[str], bool]: ctrl.dlg_config_fun(dlg_title="Please confirm", show_progress_bar=False) ctrl.display_msg_fun('<b>Read the messages displyed on your hardware wallet <br>' 'and click the confirmation button when necessary...</b>') if hw_device_id: if hw_type == HWType.trezor: from hw_intf_trezor import load_device_by_mnemonic return load_device_by_mnemonic(hw_device_id, mnemonic, pin, passphrase_enbled, hw_label) elif hw_type == HWType.keepkey: from hw_intf_keepkey import load_device_by_mnemonic return load_device_by_mnemonic(hw_device_id, mnemonic, pin, passphrase_enbled, hw_label) else: raise Exception('Not supported by Ledger Nano S.') else: raise Exception('Not connected to a hardware wallet') if hw_type == HWType.ledger_nano_s: import hw_intf_ledgernano hw_intf_ledgernano.load_device_by_mnemonic(mnemonic_words, pin, passphrase, secondary_pin) return hw_device_id, False else: return WndUtils.run_thread_dialog(load, (hw_device_id, mnemonic_words, pin, passphrase_enbled, hw_label), True)
def on_btnChooseFirmwareFile_clicked(self): file_name = WndUtils.open_file_query( self.parent_dialog, self.app_config, message='Enter the firmware file name.', directory=None, filter='All Files (*.*)', initial_filter='All Files (*.*)') if file_name: self.selected_firmware_source_file = file_name self.edtFirmwareFilePath.setText(file_name)
def ask_for_word_callback(msg: str, wordlist: List[str]) -> str: def dlg(): ui = hw_word_dlg.HardwareWalletWordDlg(msg, wordlist) if ui.exec_(): return ui.get_word() else: return None if threading.current_thread() != threading.main_thread(): return WndUtils.call_in_main_thread(dlg) else: return dlg()
def __init__(self, parent, app_config: AppConfig): QDialog.__init__(self, parent=parent) Ui_ConfigDlg.__init__(self) WndUtils.__init__(self, app_config) self.app_config = app_config self.main_window = parent self.local_config = AppConfig( app_config.internal_ui_dark_mode_activated) self.local_config.copy_from(app_config) # list of connections from self.local_config.dash_net_configs split on separate lists for mainnet and testnet self.connections_mainnet = [] self.connections_testnet = [] self.connections_current = None self.current_network_cfg: Optional[DashNetworkConnectionCfg] = None # block ui controls -> cur config data copying while setting ui controls initial values self.disable_cfg_update = False self.is_modified = False self.global_options_modified = False # user modified options not related to a config file self.setupUi(self)
def __init__(self, parent) -> None: QDialog.__init__(self, parent) ui_wallet_tools_dlg.Ui_WalletToolsDlg.__init__(self) WndUtils.__init__(self, parent.app_config) self.finishing = False self.main_ui = parent self.app_config: AppConfig = parent.app_config self.current_action = ACTION_NONE self.action_widget: Optional[ActionPageBase] = None self.action_layout: Optional[QtWidgets.QVBoxLayout] = None self.hw_devices = HWDevices.get_instance() if not self.hw_devices: raise InternalError('HWDevices not initialized') self.hw_devices.save_state( ) # save the hw device currently connected in the main window self.hw_devices.set_allow_bootloader_mode(True) self.wdg_select_hw_device = CurrentHwDeviceWdg(self, self.hw_devices, True) self.hw_devices.sig_connected_hw_device_changed.connect( self.on_connected_hw_device_changed) self.setupUi(self)
def ask_for_pin_callback(msg, hide_numbers=True): def dlg(): ui = hw_pin_dlg.HardwareWalletPinDlg(msg, hide_numbers=hide_numbers) if ui.exec_(): return ui.pin else: return None if threading.current_thread() != threading.main_thread(): return WndUtils.call_in_main_thread(dlg) else: return dlg()
def ask_for_pass_callback(): def dlg(): ui = hw_pass_dlg.HardwareWalletPassDlg() if ui.exec_(): return ui.getPassphrase() else: return None if threading.current_thread() != threading.main_thread(): return WndUtils.call_in_main_thread(dlg) else: return dlg()
def update_ui(self): try: if self.cur_hw_device and self.cur_hw_device.hw_client and self.cur_hw_device.hw_type != HWType.ledger_nano: if self.current_step == Step.STEP_INPUT_OPTIONS: self.pages.setCurrentIndex(Pages.PAGE_OPTIONS.value) self.update_action_subtitle( 'enter hardware wallet options') elif self.current_step == Step.STEP_INITIALIZING_HW: self.update_action_subtitle('initializing device') self.pages.setCurrentIndex(Pages.PAGE_OPTIONS.value) elif self.current_step == Step.STEP_FINISHED: self.update_action_subtitle('finished') self.show_message_page( '<b>Hardware wallet successfully initialized.</b>') return self.show_action_page() else: self.show_message_page( 'Connect Trezor/Keepkey hardware wallet') except Exception as e: WndUtils.error_msg(str(e), True)
def __init__(self, utxos_source, main_ui): """ Constructor :param utxos_source: list of tuples (dash address, bip32 path) - from which we'll list all unspent outputs :param masternodes: list of masternodes in configuration; used for checking if txid/index is assigned to mn's collateral """ QDialog.__init__(self) WndUtils.__init__(self, main_ui.config) assert isinstance(utxos_source, list) assert isinstance(main_ui.dashd_intf, DashdInterface) self.utxos_source = utxos_source self.dashd_intf = main_ui.dashd_intf self.table_model = None self.source_address_mode = False self.utxos = [] self.masternodes = main_ui.config.masternodes self.org_message = '' self.main_ui = main_ui self.setupUi()
def on_btnFindDMNTxHash_clicked(self, checked): if self.masternode and not self.updating_ui: found_protx = None if not ((self.masternode.ip and self.masternode.port) or (self.masternode.collateralTx and self.masternode.collateralTxIndex)): WndUtils.errorMsg('To be able to locate the deterministic masternode transaction you need to ' 'provide the masternode ip + port or collateral tx + tx index.') return try: txes = self.crownd_intf.protx('list', 'registered', True) for protx in txes: state = protx.get('state') if state: if (state.get('service') == self.masternode.ip + ':' + self.masternode.port) or \ (protx.get('collateralHash') == self.masternode.collateralTx and str(protx.get('collateralIndex', '')) == self.masternode.collateralTxIndex): found_protx = protx break except Exception as e: pass if found_protx: if self.masternode.dmn_tx_hash == protx.get('proTxHash'): WndUtils.infoMsg('You have te correct DMN TX hash in the masternode configuration.') else: self.edtDMNTxHash.setText(protx.get('proTxHash')) self.masternode.dmn_tx_hash = protx.get('proTxHash') self.set_modified() else: WndUtils.warnMsg('Couldn\'t find this masternode in the list of registered deterministic masternodes.') self.set_modified()
def setupUi(self, dlg): ui_wallet_tools_dlg.Ui_WalletToolsDlg.setupUi(self, self) self.setWindowTitle("Toolbox") WndUtils.change_widget_font_attrs(self.lblMessage, point_size_diff=3, bold=True) for action in (self.actHwSettings, self.actRecoverHw, self.actInitializeHw, self.actWipeHw, self.actUpdateHwFirmware, self.actCreateRpcauth, self.actUdevRulesInfo): WndUtils.change_widget_font_attrs(action, point_size_diff=1, bold=False) self.activate_menu_page() lay = self.layout() lay.insertWidget( 1, self.wdg_select_hw_device ) # hardware wallet selection panel is inserted just below the # main title self.action_layout = QtWidgets.QVBoxLayout(self.fraActionContainer) self.action_layout.setContentsMargins(6, 6, 6, 6) self.action_layout.setSpacing(3) self.action_layout.setObjectName("action_layout") WndUtils.change_widget_font_attrs(self.lblTitle, point_size_diff=3, bold=True)
def setupUi(self, dlg): Ui_WdgRecoverHw.setupUi(self, self) self.rbSeedSourceHwScreen.toggled.connect(self.on_seed_source_change) self.rbSeedSourceAppWords.toggled.connect(self.on_seed_source_change) self.rbSeedSourceAppEntropy.toggled.connect(self.on_seed_source_change) self.pages.setCurrentIndex(Pages.PAGE_OPTIONS.value) WndUtils.set_icon(self, self.btnShowPIN, '*****@*****.**') WndUtils.set_icon(self, self.btnShowSecondaryPIN, '*****@*****.**') WndUtils.set_icon(self, self.btnShowPassphrase, '*****@*****.**') self.rbWordsCount12.toggled.connect(self.on_radio_word_count_toggled) self.rbWordsCount18.toggled.connect(self.on_radio_word_count_toggled) self.rbWordsCount24.toggled.connect(self.on_radio_word_count_toggled) self.btnShowPIN.pressed.connect( functools.partial(self.edtPrimaryPIN.setEchoMode, QLineEdit.Normal)) self.btnShowPIN.released.connect( functools.partial(self.edtPrimaryPIN.setEchoMode, QLineEdit.Password)) self.btnShowSecondaryPIN.pressed.connect( functools.partial(self.edtSecondaryPIN.setEchoMode, QLineEdit.Normal)) self.btnShowSecondaryPIN.released.connect( functools.partial(self.edtSecondaryPIN.setEchoMode, QLineEdit.Password)) self.btnShowPassphrase.pressed.connect( functools.partial(self.edtPassphrase.setEchoMode, QLineEdit.Normal)) self.btnShowPassphrase.released.connect( functools.partial(self.edtPassphrase.setEchoMode, QLineEdit.Password)) lay = self.page3.layout() lay.addWidget(self.words_wdg) self.set_word_count(self.word_count) self.update_styles()
def __init__(self, message, hide_numbers=True, window_title: str = None, max_length=12, button_heights: Optional[int] = None, parent_window: Optional[QWidget] = None, columns: int = 3): QDialog.__init__(self) QDetectThemeChange.__init__(self) ui_hw_pin_dlg.Ui_HardwareWalletPinDlg.__init__(self) WndUtils.__init__(self, app_config=None) self.pin = '' self.message = message self.hide_numbers = hide_numbers self.window_title = window_title if window_title else 'Hardware wallet PIN' self.max_length = max_length self.button_heights = button_heights self.columns = columns if columns not in (2, 3): raise Exception('Invalid number of matrix columns') self.setupUi(self)
def __init__(self, main_dlg, config: AppConfig, fixd_intf: FixdInterface, masternode: MasternodeConfig, on_mn_config_updated_callback: Callable): QDialog.__init__(self, main_dlg) ui_upd_mn_service_dlg.Ui_UpdMnServiceDlg.__init__(self) WndUtils.__init__(self, main_dlg.config) self.main_dlg = main_dlg self.masternode = masternode self.app_config = config self.fixd_intf = fixd_intf self.on_mn_config_updated_callback = on_mn_config_updated_callback self.dmn_protx_hash = self.masternode.dmn_tx_hash self.dmn_actual_operator_pubkey = "" self.dmn_actual_operator_reward = 0 self.dmn_new_operator_payout_address = '' self.dmn_prev_ip_port = self.masternode.ip + ':' + str( self.masternode.port) self.dmn_new_ip = '' self.dmn_new_port = '' self.upd_payout_active = False self.show_manual_commands = False self.setupUi()
def on_wipe_code_enable_disable(self, _): if self.cur_hw_device and self.cur_hw_device.hw_client: if self.hw_opt_wipe_code_protection is True: # disable passphrase if WndUtils.query_dlg( 'Do you really want to disable wipe code?', buttons=QMessageBox.Yes | QMessageBox.Cancel, default_button=QMessageBox.Cancel, icon=QMessageBox.Warning) == QMessageBox.Yes: self.hw_devices.set_wipe_code(self.cur_hw_device, remove=True) self.update_ui() elif self.hw_opt_wipe_code_protection is False: # enable passphrase if WndUtils.query_dlg( 'Do you really want to enable wipe code?', buttons=QMessageBox.Yes | QMessageBox.Cancel, default_button=QMessageBox.Cancel, icon=QMessageBox.Warning) == QMessageBox.Yes: self.hw_devices.set_wipe_code(self.cur_hw_device, remove=False) self.update_ui()
def on_passphrase_alwaysondevice_enable_disable(self, _): if self.cur_hw_device and self.cur_hw_device.hw_client: if self.hw_opt_passphrase_always_on_device is True: # disable passphrase if WndUtils.query_dlg( 'Do you really want to disable passphrase always on device option?', buttons=QMessageBox.Yes | QMessageBox.Cancel, default_button=QMessageBox.Cancel, icon=QMessageBox.Warning) == QMessageBox.Yes: self.hw_devices.set_passphrase_always_on_device( self.cur_hw_device, enabled=False) self.update_ui() elif self.hw_opt_passphrase_always_on_device is False: # enable passphrase if WndUtils.query_dlg( 'Do you really want to enable passphrase always on device option?', buttons=QMessageBox.Yes | QMessageBox.Cancel, default_button=QMessageBox.Cancel, icon=QMessageBox.Warning) == QMessageBox.Yes: self.hw_devices.set_passphrase_always_on_device( self.cur_hw_device, enabled=True) self.update_ui()
def on_sd_card_protection_enable_disable(self, _): if self.cur_hw_device and self.cur_hw_device.hw_client: if self.hw_opt_sd_protection is True: # disable passphrase if WndUtils.query_dlg( 'Do you really want to disable SD card protection?', buttons=QMessageBox.Yes | QMessageBox.Cancel, default_button=QMessageBox.Cancel, icon=QMessageBox.Warning) == QMessageBox.Yes: self.hw_devices.set_sd_protect(self.cur_hw_device, 'disable') self.update_ui() elif self.hw_opt_sd_protection is False: # enable passphrase if WndUtils.query_dlg( 'Do you really want to enable SD card protection?', buttons=QMessageBox.Yes | QMessageBox.Cancel, default_button=QMessageBox.Cancel, icon=QMessageBox.Warning) == QMessageBox.Yes: self.hw_devices.set_sd_protect(self.cur_hw_device, 'enable') self.update_ui()
def hw_encrypt_value(hw_session: HwSessionInfo, bip32_path_n: List[int], label: str, value: ByteString, ask_on_encrypt=True, ask_on_decrypt=True) -> Tuple[bytearray, bytearray]: """Encrypts a value with a hardware wallet. :param hw_session: :param bip32_path_n: bip32 path of the private key used for encryption :param label: key (in the meaning of key-value) used for encryption :param value: value being encrypted :param ask_on_encrypt: see Trezor doc :param ask_on_decrypt: see Trezor doc """ def encrypt(ctrl, hw_session: HwSessionInfo, bip32_path_n: List[int], label: str, value: bytearray): ctrl.dlg_config_fun(dlg_title="Data encryption", show_progress_bar=False) ctrl.display_msg_fun(f'<b>Encrypting \'{label}\'...</b>' f'<br><br>Enter the hardware wallet PIN/passphrase (if needed) to encrypt data.<br><br>' f'<b>Note:</b> encryption passphrase is independent from the wallet passphrase <br>' f'and can vary for each encrypted file.') if hw_session.hw_type == HWType.trezor: from trezorlib import misc, btc from trezorlib import exceptions try: client = hw_session.hw_client data = misc.encrypt_keyvalue(client, bip32_path_n, label, value, ask_on_encrypt, ask_on_decrypt) pub_key = btc.get_public_node(client, bip32_path_n).node.public_key return data, pub_key except (CancelException, exceptions.Cancelled): raise CancelException() elif hw_session.hw_type == HWType.keepkey: client = hw_session.hw_client data = client.encrypt_keyvalue(bip32_path_n, label, value, ask_on_encrypt, ask_on_decrypt) pub_key = client.get_public_node(bip32_path_n).node.public_key return data, pub_key elif hw_session.hw_type == HWType.ledger_nano_s: raise Exception('Feature not available for Ledger Nano S.') else: raise Exception('Invalid HW type: ' + str(hw_session)) if len(value) != 32: raise ValueError("Invalid password length (<> 32).") return WndUtils.run_thread_dialog(encrypt, (hw_session, bip32_path_n, label, value), True, force_close_dlg_callback=partial(cancel_hw_thread_dialog, hw_session.hw_client), show_window_delay_ms=200)
def get_address(hw_session: HwSessionInfo, bip32_path: str, show_display: bool = False, message_to_display: str = None): def _get_address(ctrl, hw_session: HwSessionInfo, bip32_path: str, show_display: bool = False, message_to_display: str = None): if ctrl: ctrl.dlg_config_fun(dlg_title="Please confirm", show_progress_bar=False) if message_to_display: ctrl.display_msg_fun(message_to_display) else: ctrl.display_msg_fun('<b>Click the confirmation button on your hardware wallet to exit...</b>') client = hw_session.hw_client if client: if isinstance(bip32_path, str): bip32_path.strip() if bip32_path.lower().find('m/') >= 0: # removing m/ prefix because of keepkey library bip32_path = bip32_path[2:] if hw_session.app_config.hw_type == HWType.trezor: from trezorlib import btc if isinstance(bip32_path, str): bip32_path = dash_utils.bip32_path_string_to_n(bip32_path) return btc.get_address(client, hw_session.app_config.hw_coin_name, bip32_path, show_display) elif hw_session.app_config.hw_type == HWType.keepkey: if isinstance(bip32_path, str): bip32_path = dash_utils.bip32_path_string_to_n(bip32_path) return client.get_address(hw_session.app_config.hw_coin_name, bip32_path, show_display) elif hw_session.app_config.hw_type == HWType.ledger_nano_s: import hw_intf_ledgernano as ledger if isinstance(bip32_path, list): # ledger requires bip32 path argument as a string bip32_path = bip32_path_n_to_string(bip32_path) adr_pubkey = ledger.get_address_and_pubkey(client, bip32_path) return adr_pubkey.get('address') else: raise Exception('Unknown hardware wallet type: ' + hw_session.app_config.hw_type) else: raise Exception('HW client not open.') if show_display: return WndUtils.run_thread_dialog(_get_address, (hw_session, bip32_path, show_display, message_to_display), True) else: return _get_address(None, hw_session, bip32_path, show_display, message_to_display)
def __init__(self, config, window, connection=None, on_connection_begin_callback=None, on_connection_try_fail_callback=None, on_connection_finished_callback=None): WndUtils.__init__(self, app_path=config.app_path) assert isinstance(config, AppConfig) self.config = config # conn configurations are used from the first item in the list; if one fails, then next is taken if connection: # this parameter is used for testing specific connection self.connections = [connection] else: # get connection list orderd by priority of use self.connections = self.config.get_ordered_conn_list() self.cur_conn_index = 0 if self.connections: self.cur_conn_def = self.connections[self.cur_conn_index] else: self.cur_conn_def = None # below is the connection with which particular RPC call has started; if connection is switched because of # problems with some nodes, switching stops if we close round and return to the starting connection self.starting_conn = None self.ssh = None self.window = window self.active = False self.rpc_url = None self.proxy = None self.http_conn = None # HTTPConnection object passed to the AuthServiceProxy (for convinient connection reset) self.on_connection_begin_callback = on_connection_begin_callback self.on_connection_try_fail_callback = on_connection_try_fail_callback self.on_connection_finished_callback = on_connection_finished_callback self.last_error_message = None
def upload_firmware_thread(self, ctrl: CtrlObject): """ Thread that performs upload of the selected firmware to the hardware wallet device. The device has to be in bootloader mode. """ def add_info(msg: str): def append_message_mainth(msg_: str): t = self.lblUploadFirmwareMessage.text() t += f'<div>{msg}</div>' self.lblUploadFirmwareMessage.setText(t) WndUtils.call_in_main_thread(append_message_mainth, msg) update_ok = False try: self.hw_conn_change_allowed = False add_info('Uploading new firmware.<br><br><b>Click the confirmation button on your hardware wallet device ' 'if necessary.</b>') if self.cur_hw_device.hw_type == HWType.trezor: update_ok = self.cur_hw_device.hw_client.firmware_update(self.selected_firmware_source_web.fingerprint, self.firmware_data) elif self.cur_hw_device.hw_type == HWType.keepkey: update_ok = self.cur_hw_device.hw_client.firmware_update(BytesIO(self.firmware_data)) else: WndUtils.call_in_main_thread(self.go_to_prev_step) raise Exception('Invalid hardware wallet type') if not update_ok: WndUtils.error_msg('Operation failed. Look into the log file for details.') except CancelException: pass except Exception as e: WndUtils.error_msg('Operation failed with the following error: ' + str(e)) finally: self.hw_conn_change_allowed = True self.upload_firmware_thread_obj = None if update_ok: WndUtils.call_in_main_thread(self.go_to_next_step) else: WndUtils.call_in_main_thread(self.go_to_prev_step)
def hw_decrypt_value(hw_session: HwSessionInfo, bip32_path_n: List[int], label: str, value: ByteString, ask_on_encrypt=True, ask_on_decrypt=True) -> Tuple[bytearray, bytearray]: """ :param hw_session: :param passphrase_encoding: (for Keepkey only) it allows forcing the passphrase encoding compatible with BIP-39 standard (NFKD), which is used by Trezor devices; by default Keepkey uses non-standard encoding (NFC). :param bip32_path_n: bip32 path of the private key used for encryption :param label: key (in the meaning of key-value) used for encryption :param value: encrypted value to be decrypted, :param ask_on_encrypt: see Trezor doc :param ask_on_decrypt: see Trezor doc """ def decrypt(ctrl, hw_session: HwSessionInfo, bip32_path_n: List[int], label: str, value: bytearray): ctrl.dlg_config_fun(dlg_title="Data decryption", show_progress_bar=False) ctrl.display_msg_fun(f'<b>Decrypting \'{label}\'...</b><br><br>Enter the hardware wallet PIN/passphrase ' f'(if needed)<br> and click the confirmation button to decrypt data.') if hw_session.hw_type == HWType.trezor: from trezorlib import misc, btc from trezorlib import exceptions try: client = hw_session.hw_client data = misc.decrypt_keyvalue(client, bip32_path_n, label, value, ask_on_encrypt, ask_on_decrypt) pub_key = btc.get_public_node(client, bip32_path_n).node.public_key return data, pub_key except (CancelException, exceptions.Cancelled): raise CancelException() elif hw_session.hw_type == HWType.keepkey: client = hw_session.hw_client data = client.decrypt_keyvalue(bip32_path_n, label, value, ask_on_encrypt, ask_on_decrypt) pub_key = client.get_public_node(bip32_path_n).node.public_key return data, pub_key elif hw_session.hw_type == HWType.ledger_nano_s: raise Exception('Feature not available for Ledger Nano S.') else: raise Exception('Invalid HW type: ' + str(hw_session)) if len(value) != 32: raise ValueError("Invalid password length (<> 32).") return WndUtils.run_thread_dialog(decrypt, (hw_session, bip32_path_n, label, value), True, force_close_dlg_callback=partial(cancel_hw_thread_dialog, hw_session.hw_client))
def generate_priv_key(self, pk_type:str, edit_control: QLineEdit, compressed: bool): if edit_control.text(): if WndUtils.queryDlg( f'This will overwrite the current {pk_type} private key value. Do you really want to proceed?', buttons=QMessageBox.Yes | QMessageBox.Cancel, default_button=QMessageBox.Yes, icon=QMessageBox.Warning) != QMessageBox.Yes: return None if pk_type == 'operator': pk = crown_utils.generate_bls_privkey() else: pk = crown_utils.generate_wif_privkey(self.app_config.crown_network, compressed=compressed) edit_control.setText(pk) return pk
def reset_device(hw_type: HWType, hw_device_id: str, word_count: int, passphrase_enabled: bool, pin_enabled: bool, hw_label: str, parent_window = None) -> Tuple[Optional[str], bool]: """ Initialize device with a newly generated words. :param hw_type: app_config.HWType :param hw_device_id: id of the device selected by the user (TrezorClient, KeepkeyClient); None for Ledger Nano S :param word_count: number of words (12/18/24) :param passphrase_enbled: if True, hw will have passphrase enabled (Trezor/Keepkey) :param pin_enabled: if True, hw will have pin enabled (Trezor/Keepkey) :param hw_label: label for device (Trezor/Keepkey) :param parent_window: ref to a window according to which will be centered message dialogs created here :return: Tuple Ret[0]: Device id. If a device is wiped before initializing with mnemonics, a new device id is generated. It's returned to the caller. Ret[1]: True, if the user cancelled the operation. In this situation we deliberately don't raise the 'cancelled' exception, because in the case of changing of the device id (when wiping) we want to pass it back to the caller function. Ret[0] and Ret[1] are None for Ledger devices. """ def load(ctrl, hw_type: HWType, hw_device_id: str, strength: int, passphrase_enabled: bool, pin_enabled: bool, hw_label: str) -> Tuple[Optional[str], bool]: ctrl.dlg_config_fun(dlg_title="Please confirm", show_progress_bar=False) ctrl.display_msg_fun('<b>Read the messages displyed on your hardware wallet <br>' 'and click the confirmation button when necessary...</b>') if hw_device_id: if hw_type == HWType.trezor: from hw_intf_trezor import reset_device return reset_device(hw_device_id, strength, passphrase_enabled, pin_enabled, hw_label) elif hw_type == HWType.keepkey: from hw_intf_keepkey import reset_device return reset_device(hw_device_id, strength, passphrase_enabled, pin_enabled, hw_label) else: raise Exception('Not supported by Ledger Nano S.') else: raise Exception('Not connected to a hardware wallet') if hw_type == HWType.ledger_nano_s: raise Exception('Not supported by Ledger Nano S.') else: if word_count not in (12, 18, 24): raise Exception('Invalid word count.') strength = {24: 32, 18: 24, 12: 16}.get(word_count) * 8 return WndUtils.run_thread_dialog(load, (hw_type, hw_device_id, strength, passphrase_enabled, pin_enabled, hw_label), True, center_by_window=parent_window)
def sign_tx(hw_session: HwSessionInfo, utxos_to_spend: List[UtxoType], tx_outputs: List[TxOutputType], tx_fee): """ Creates a signed transaction. :param main_ui: Main window for configuration data :param utxos_to_spend: list of utxos to send :param tx_outputs: destination addresses. Fields: 0: dest FIX address. 1: the output value in satoshis, 2: the bip32 path of the address if the output is the change address or None otherwise :param tx_fee: transaction fee :param rawtransactions: dict mapping txid to rawtransaction :return: tuple (serialized tx, total transaction amount in satoshis) """ def sign(ctrl): ctrl.dlg_config_fun(dlg_title="Confirm transaction signing.", show_progress_bar=False) ctrl.display_msg_fun( '<b>Click the confirmation button on your hardware wallet<br>' 'and wait for the transaction to be signed...</b>') if hw_session.app_config.hw_type == HWType.trezor: import hw_intf_trezor as trezor return trezor.sign_tx(hw_session, utxos_to_spend, tx_outputs, tx_fee) elif hw_session.app_config.hw_type == HWType.keepkey: import hw_intf_keepkey as keepkey return keepkey.sign_tx(hw_session, utxos_to_spend, tx_outputs, tx_fee) elif hw_session.app_config.hw_type == HWType.ledger_nano_s: import hw_intf_ledgernano as ledger return ledger.sign_tx(hw_session, utxos_to_spend, tx_outputs, tx_fee) else: logging.error('Invalid HW type: ' + str(hw_session.app_config.hw_type)) # execute the 'prepare' function, but due to the fact that the call blocks the UI until the user clicks the HW # button, it's done inside a thread within a dialog that shows an appropriate message to the user sig = WndUtils.run_thread_dialog(sign, (), True, force_close_dlg_callback=partial( cancel_hw_thread_dialog, hw_session.hw_client)) return sig
def ask_for_pass_callback(pass_available_on_device: bool = False): def dlg(): ui = hw_pass_dlg.HardwareWalletPassDlg(pass_available_on_device) if ui.exec_(): if ui.getEnterOnDevice(): return PASSPHRASE_ON_DEVICE else: return ui.getPassphrase() else: return None if threading.current_thread() != threading.main_thread(): return WndUtils.call_in_main_thread(dlg) else: return dlg()