Пример #1
0
    def get_session_info_trezor(get_public_node_fun, hw_session: HwSessionInfo,
                                hw_client):
        nonlocal hw_type

        def call_get_public_node(ctrl, get_public_node_fun, path_n):
            pk = get_public_node_fun(path_n).node.public_key
            return pk

        path = fix_utils.get_default_bip32_base_path(
            hw_session.app_config.fix_network)
        path_n = fix_utils.bip32_path_string_to_n(path)

        # show message for Trezor T device while waiting for the user to choose the passphrase input method
        pub = WndUtils.run_thread_dialog(call_get_public_node,
                                         (get_public_node_fun, path_n),
                                         title=DEFAULT_HW_BUSY_TITLE,
                                         text=DEFAULT_HW_BUSY_MESSAGE,
                                         force_close_dlg_callback=partial(
                                             cancel_hw_thread_dialog,
                                             hw_client),
                                         show_window_delay_ms=1000)

        if pub:
            hw_session.set_base_info(path, pub)
        else:
            raise Exception('Couldn\'t read data from the hardware wallet.')
Пример #2
0
def hw_sign_message(hw_session: HwSessionInfo, bip32path, message, display_label: str = None):
    def sign(ctrl, display_label):
        ctrl.dlg_config_fun(dlg_title="Confirm message signing.", show_progress_bar=False)
        if not display_label:
            if hw_session.app_config.hw_type == HWType.ledger_nano_s:
                message_hash = hashlib.sha256(message.encode('ascii')).hexdigest().upper()
                display_label = '<b>Click the confirmation button on your hardware wallet to sign the message...</b>' \
                                '<br><br><b>Message:</b><br><span>' + message + '</span><br><br><b>SHA256 hash</b>:' \
                                                                                '<br>' + message_hash
            else:
                display_label = '<b>Click the confirmation button on your hardware wallet to sign the message...</b>'
        ctrl.display_msg_fun(display_label)

        if hw_session.app_config.hw_type == HWType.trezor:
            import hw_intf_trezor as trezor

            return trezor.sign_message(hw_session, bip32path, message)

        elif hw_session.app_config.hw_type == HWType.keepkey:
            import hw_intf_keepkey as keepkey

            return keepkey.sign_message(hw_session, bip32path, message)

        elif hw_session.app_config.hw_type == HWType.ledger_nano_s:
            import hw_intf_ledgernano as ledger

            return ledger.sign_message(hw_session, bip32path, message)
        else:
            logging.error('Invalid HW type: ' + str(hw_session.app_config.hw_type))

    # execute the 'sign' 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, (display_label,), True)
    return sig
def hw_sign_message(hw_session: HwSessionInfo, bip32path, message, display_label: str = None):
    def sign(ctrl, display_label):
        ctrl.dlg_config_fun(dlg_title="Confirm message signing.", show_progress_bar=False)
        if display_label:
            ctrl.display_msg_fun(display_label)
        else:
            ctrl.display_msg_fun('<b>Click the confirmation button on your hardware wallet...</b>')

        if hw_session.app_config.hw_type == HWType.trezor:
            import hw_intf_trezor as trezor

            return trezor.sign_message(hw_session, bip32path, message)

        elif hw_session.app_config.hw_type == HWType.keepkey:
            import hw_intf_keepkey as keepkey

            return keepkey.sign_message(hw_session, bip32path, message)

        elif hw_session.app_config.hw_type == HWType.ledger_nano_s:
            import hw_intf_ledgernano as ledger

            return ledger.sign_message(hw_session, bip32path, message)
        else:
            logging.error('Invalid HW type: ' + str(hw_session.app_config.hw_type))

    # execute the 'sign' 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, (display_label,), True)
    return sig
Пример #4
0
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:
                raise Exception('Feature no longer available for Trezor')
            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 HWNotConnectedException()

    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)
Пример #5
0
def hw_app_install(hw_session: HwSessionInfo, device: str, testnet: bool):
    def install(ctrl, device: str, testnet: bool) -> Tuple[int, str]:
        """
        Returns the result code and respective message after attempting an app install.
        """

        if device == "nanos":
            from hw_intf_ledgernano import Installer
            ledger = Installer(ctrl, testnet)

            name = "GINcoin" if not testnet else "GINcoin Testnet"
            tn = "" if not testnet else " testnet"
            ctrl.dlg_config_fun(dlg_title=f"Install {name}",
                                show_progress_bar=False,
                                min_width=250)
            ctrl.display_msg_fun(f"<b>Initialising...</b>")
            results = {
                0x0000:
                f"{name} app installed successfully! REMINDER: This install method is not officially endorsed by Ledger. You will see a 'non genuine' confirmation prompt upon launch of the app. This is normal, and functionality is unchanged. This prompt will not appear when installed with the official Ledger Live Manager.",
                0x0001:
                f"Error: {name} app installation failed.",
                0x0002:
                f"Error: {name} app post-install verification failed! Please remove the app (with `uninstall nanos{tn}`) and then report this issue.",
                0x0003:
                f"Error: Your version of the Bitcoin app is unknown. Please update both GINware and the Bitcoin app on your Ledger device, and try again. If the issue persists, please report this issue.",
                0x0004:
                f"Error: App validation hashes not found!",
                0x0005:
                f"Error: {name} app pre-install validation failed! Please report this issue.",
                0x6484:
                f"Error: Are you sure you're using the latest firmware? Please update your Ledger device's firmware with the Ledger Live Manager.",
                0x6985:
                f"Error: Cancelled by user.",
                0x6a81:
                f"Error: The {name} app already seems to be installed. Please remove the {name} app first (with `uninstall nanos{tn}`).",
                0x6a83:
                f"Error: Please install the Bitcoin app first, through the Manager tab in Ledger Live.",
                0x6a84:
                f"Error: Insufficient space on device.",
                0x6a85:
                f"Error: Insufficient space on device.",
                0x6d00:
                f"Error: Please close any open app on your Ledger Nano S device and try again.",
                0x6f00:
                f"Error: Please connect and unlock your Ledger Nano S device."
            }
            res = ledger.install()
        if res == 0: return (0, results.get(0))
        elif results.get(res) == None:
            return (2, results.get(1) + " (code: " + hex(res) + ")")
        else:
            return (2, results.get(res))

    return WndUtils.run_thread_dialog(install, (device, testnet),
                                      True,
                                      force_close_dlg_callback=partial(
                                          cancel_hw_thread_dialog,
                                          hw_session.hw_client))
Пример #6
0
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)
Пример #7
0
    def on_btnLocateCollateral_clicked(self, checked):
        break_scanning = False

        if not self.main_dlg.connect_hardware_wallet():
            return

        def do_break_scanning():
            nonlocal break_scanning
            break_scanning = True
            return False

        def check_break_scanning():
            nonlocal break_scanning
            return break_scanning

        def apply_utxo(utxo):
            self.masternode.collateralAddress = utxo.address
            self.edtCollateralAddress.setText(utxo.address)
            self.masternode.collateralBip32Path = utxo.bip32_path
            self.edtCollateralPath.setText(utxo.bip32_path)
            self.masternode.collateralTx = utxo.txid
            self.edtCollateralTxHash.setText(utxo.txid)
            self.masternode.collateralTxIndex = str(utxo.output_index)
            self.edtCollateralTxIndex.setText(str(utxo.output_index))
            self.update_ui_controls_state()
            self.set_modified()

        bip44_wallet = Bip44Wallet(self.app_config.hw_coin_name, self.main_dlg.hw_session,
                                   self.app_config.db_intf, self.crownd_intf, self.app_config.crown_network)

        utxos = WndUtils.run_thread_dialog(
            self.get_collateral_tx_address_thread,
            (bip44_wallet, check_break_scanning, self.edtCollateralAddress.text()),
            True, force_close_dlg_callback=do_break_scanning)

        if utxos:
            if len(utxos) == 1 and \
                    (not self.masternode.collateralAddress or
                     (utxos[0].address_obj and self.masternode.collateralAddress == utxos[0].address_obj.address)) \
                    and (not self.masternode.collateralTx or utxos[0].txid == self.masternode.collateralTx):
                apply_utxo(utxos[0])
                return

            dlg = ListCollateralTxsDlg(self, self.masternode, self.app_config, False, utxos)
            if dlg.exec_():
                utxo = dlg.get_selected_utxo()
                if utxo:
                    apply_utxo(utxo)
        else:
            if utxos is not None:
                WndUtils.warnMsg('Couldn\'t find any 10000 Crown UTXO in your wallet.')
Пример #8
0
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)
Пример #9
0
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))
Пример #10
0
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)
Пример #11
0
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
Пример #12
0
    def get_session_info_trezor(get_public_node_fun, hw_session: HwSessionInfo):
        nonlocal hw_type

        def call_get_public_node(ctrl, get_public_node_fun, path_n):
            pk = get_public_node_fun(path_n).node.public_key
            return pk

        path = dash_utils.get_default_bip32_base_path(hw_session.app_config.dash_network)
        path_n = dash_utils.bip32_path_string_to_n(path)

        # show message for Trezor T device while waiting for the user to choose the passphrase input method
        pub = WndUtils.run_thread_dialog(call_get_public_node, (get_public_node_fun, path_n), title='Confirm',
                                         text='<b>Complete the action on your hardware wallet device</b>',
                                         show_window_delay_ms=1000)

        hw_session.set_base_info(path, pub)
Пример #13
0
    def on_btnLocateCollateral_clicked(self, checked):
        if not self.main_dlg.connect_hardware_wallet():
            return

        def apply_utxo(utxo):
            self.masternode.collateralAddress = utxo.address
            self.edtCollateralAddress.setText(utxo.address)
            self.masternode.collateralBip32Path = utxo.bip32_path
            self.edtCollateralPath.setText(utxo.bip32_path)
            self.masternode.collateralTx = utxo.txid
            self.edtCollateralTxHash.setText(utxo.txid)
            self.masternode.collateralTxIndex = str(utxo.output_index)
            self.edtCollateralTxIndex.setText(str(utxo.output_index))
            self.update_ui()
            self.set_modified()

        bip44_wallet = Bip44Wallet(self.app_config.hw_coin_name,
                                   self.main_dlg.hw_session,
                                   self.app_config.db_intf, self.dashd_intf,
                                   self.app_config.dash_network)

        utxos = WndUtils.run_thread_dialog(
            self.get_collateral_tx_address_thread, (bip44_wallet, ), True)
        if utxos:
            if len(
                    utxos
            ) == 1 and not self.masternode.collateralAddress and not self.masternode.collateralTx:
                used = False
                for mn in self.app_config.masternodes:
                    if utxos[0].address == mn.collateralAddress or mn.collateralTx + '-' + str(mn.collateralTxIndex) == \
                       utxos[0].txid + '-' + str(utxos[0].output_index):
                        used = True
                        break
                if not used:
                    apply_utxo(utxos[0])
                    return

            dlg = ListCollateralTxsDlg(self, self.masternode, self.app_config,
                                       False, utxos)
            if dlg.exec_():
                utxo = dlg.get_selected_utxo()
                if utxo:
                    apply_utxo(utxo)
        else:
            if utxos is not None:
                WndUtils.warnMsg(
                    'Couldn\'t find any 1000 Dash UTXO in your wallet.')
Пример #14
0
def wipe_device(hw_type: HWType,
                hw_device_id: Optional[str],
                parent_window=None) -> Tuple[Optional[str], bool]:
    """
    Wipes the hardware wallet device.
    :param hw_type: app_config.HWType
    :param hw_device_id: id of the device selected by the user (TrezorClient, KeepkeyClient)
    :param parent_window: ref to a window according to which will be centered message dialogs created here
    :return: Tuple
        Ret[0]: Device id. After wiping a new device id is generated, which is 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.
    """
    def wipe(ctrl):
        ctrl.dlg_config_fun(dlg_title="Confirm wiping device.",
                            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_type == HWType.trezor:

            from hw_intf_trezor import wipe_device
            return wipe_device(hw_device_id)

        elif hw_type == HWType.keepkey:

            from hw_intf_keepkey import wipe_device
            return wipe_device(hw_device_id)

        elif hw_type == HWType.ledger_nano_s:

            raise Exception('Not supported by Ledger Nano S.')

        else:
            raise Exception('Invalid HW type: ' + str(hw_type))

    # execute the 'wipe' inside a thread to avoid blocking UI
    return WndUtils.run_thread_dialog(wipe, (),
                                      True,
                                      center_by_window=parent_window)
Пример #15
0
def hw_app_uninstall(hw_session: HwSessionInfo, device: str, testnet: bool):
    def uninstall(ctrl, device: str, testnet: bool) -> Tuple[int, str]:
        """
        Returns the result code and respective message after attempting an app removal.
        """

        if device == "nanos":
            from hw_intf_ledgernano import Installer
            ledger = Installer(ctrl, testnet)

            name = "GINcoin" if not testnet else "GINcoin Testnet"
            ctrl.dlg_config_fun(dlg_title=f"Uninstall {name}",
                                show_progress_bar=False,
                                min_width=250)
            ctrl.display_msg_fun(f"<b>Initialising...</b>")
            results = {
                0x0000:
                f"{name} app removed.",
                0x0001:
                f"Error: {name} app removal failed.",
                0x6484:
                f"Error: Are you sure you're using the latest firmware? Please update your Ledger device's firmware with the Ledger Live Manager.",
                0x6985:
                f"Error: Cancelled by user.",
                0x6d00:
                f"Error: Please close any open app on your Ledger Nano S device and try again.",
                0x6f00:
                f"Error: Please connect and unlock your Ledger Nano S device."
            }
            res = ledger.uninstall()
        if res == 0: return (0, results.get(0))
        elif results.get(res) == None:
            return (2, results.get(1) + " (code: " + hex(res) + ")")
        else:
            return (2, results.get(res))

    return WndUtils.run_thread_dialog(uninstall, (device, testnet),
                                      True,
                                      force_close_dlg_callback=partial(
                                          cancel_hw_thread_dialog,
                                          hw_session.hw_client))
    def verify_data(self):
        self.dmn_collateral_tx = self.edtCollateralTx.text().strip()
        try:
            self.dmn_collateral_tx_index = int(self.edtCollateralIndex.text())
            if self.dmn_collateral_tx_index < 0:
                raise Exception('Invalid transaction index')
        except Exception:
            self.edtCollateralIndex.setFocus()
            raise Exception(
                'Invalid collateral transaction index: should be integer greater or equal 0.'
            )

        try:
            self.dmn_ip = self.edtIP.text().strip()
            if self.dmn_ip:
                ipaddress.ip_address(self.dmn_ip)
        except Exception as e:
            self.edtIP.setFocus()
            raise Exception('Invalid masternode IP address: %s.' % str(e))

        try:
            if self.dmn_ip:
                self.dmn_tcp_port = int(self.edtPort.text())
            else:
                self.dmn_tcp_port = None
        except Exception:
            self.edtPort.setFocus()
            raise Exception('Invalid TCP port: should be integer.')

        self.dmn_owner_payout_addr = self.edtPayoutAddress.text().strip()
        if not validate_address(self.dmn_owner_payout_addr,
                                self.app_config.dash_network):
            self.edtPayoutAddress.setFocus()
            raise Exception('Invalid owner payout address.')

        if self.chbWholeMNReward.isChecked():
            self.dmn_operator_reward = 0
        else:
            self.dmn_operator_reward = self.edtOperatorReward.value()
            if self.dmn_operator_reward > 100 or self.dmn_operator_reward < 0:
                self.edtOperatorReward.setFocus()
                raise Exception(
                    'Invalid operator reward value: should be a value between 0 and 100.'
                )

        self.dmn_owner_privkey = self.edtOwnerKey.text().strip()
        if not validate_wif_privkey(self.dmn_owner_privkey,
                                    self.app_config.dash_network):
            self.edtOwnerKey.setFocus()
            self.upd_owner_key_info(True)
            raise Exception('Invalid owner private key.')
        else:
            self.dmn_owner_address = wif_privkey_to_address(
                self.dmn_owner_privkey, self.app_config.dash_network)

        try:
            self.dmn_operator_privkey = self.edtOperatorKey.text().strip()
            self.dmn_operator_pubkey = bls_privkey_to_pubkey(
                self.dmn_operator_privkey)
        except Exception as e:
            self.upd_operator_key_info(True)
            self.edtOperatorKey.setFocus()
            raise Exception('Invalid operator private key: ' + str(e))

        self.dmn_voting_privkey = self.edtVotingKey.text().strip()
        if not validate_wif_privkey(self.dmn_voting_privkey,
                                    self.app_config.dash_network):
            self.upd_voting_key_info(True)
            self.edtVotingKey.setFocus()
            raise Exception('Invalid voting private key.')
        else:
            self.dmn_voting_address = wif_privkey_to_address(
                self.dmn_voting_privkey, self.app_config.dash_network)

        self.btnContinue.setEnabled(False)
        self.btnContinue.repaint()

        ret = WndUtils.run_thread_dialog(self.get_collateral_tx_address_thread,
                                         (), True)
        self.btnContinue.setEnabled(True)
        self.btnContinue.repaint()
        return ret
Пример #17
0
def recover_device_with_seed_input(dongle: HIDDongleHIDAPI,
                                   mnemonic_words: str, pin: str,
                                   passphrase: str, secondary_pin: str):
    """
    Initialize Ledger Nano S device with a list of mnemonic words.
    :param mnemonic_words: 12, 18 or 24 mnemonic words separated with spaces to initialise device.
    :param pin: PIN to be set in the device (4- or 8-character string)
    :param passphrase: Passphrase to be set in the device or empty.
    :param secondary_pin: Secondary PIN to activate passph. It's required if 'passph' is set.
    """
    def process(ctrl):
        ctrl.dlg_config(dlg_title="Please confirm", show_progress_bar=False)
        ctrl.display_msg('<b>Please wait while initializing device...</b>')

        # stage 1: initialize the hardware wallet with mnemonic words
        apdudata = bytearray()
        if pin:
            apdudata += bytearray([len(pin)]) + bytearray(pin, 'utf8')
        else:
            apdudata += bytearray([0])

        # empty prefix
        apdudata += bytearray([0])

        # empty passph in this phase
        apdudata += bytearray([0])

        if mnemonic_words:
            apdudata += bytearray([len(mnemonic_words)]) + bytearray(
                mnemonic_words, 'utf8')
        else:
            apdudata += bytearray([0])

        apdu = bytearray([0xE0, 0xD0, 0x00, 0x00, len(apdudata)]) + apdudata
        dongle.exchange(apdu, timeout=3000)

        # stage 2: setup the secondary pin and the passph if provided
        if passphrase and secondary_pin:
            ctrl.display_msg(
                '<b>Configuring passphrase, enter the primary PIN on your <br>'
                'hardware wallet when asked...</b>')

            apdudata = bytearray()
            if pin:
                apdudata += bytearray([len(pin)]) + bytearray(
                    secondary_pin, 'utf8')
            else:
                apdudata += bytearray([0])

            # empty prefix
            apdudata += bytearray([0])

            if passphrase:
                _passph = unicodedata.normalize('NFKD', passphrase)
                apdudata += bytearray([len(_passph)]) + bytearray(
                    _passph, 'utf8')
            else:
                apdudata += bytearray([0])

            # empty mnemonic words in this phase
            apdudata += bytearray([0])

            apdu = bytearray([0xE0, 0xD0, 0x01, 0x00,
                              len(apdudata)]) + apdudata
            dongle.exchange(apdu, timeout=3000)

            device_id = dongle.__getattribute__('hidDevicePath')
            return device_id

    was_open = is_dongle_open(dongle)
    try:
        open_dongle(dongle)
        return WndUtils.run_thread_dialog(process, (), True)
    except BTChipException as e:
        if e.message in ('Invalid status 6982', 'Invalid status 6d00'):
            raise Exception(
                'Operation failed with the following error: %s. \n\nMake sure you have reset the device '
                'and started it in recovery mode.' % e.message)
        else:
            raise
    finally:
        if not was_open and is_dongle_open(dongle):
            dongle.close()
Пример #18
0
def load_device_by_mnemonic(mnemonic_words: str, pin: str, passphrase: str,
                            secondary_pin: str):
    """
    Initialise Ledger Nano S device with a list of mnemonic words.
    :param mnemonic_words: 12, 18 or 24 mnemonic words separated with spaces to initialise device.
    :param pin: PIN to be set in the device (4- or 8-character string)
    :param passphrase: Passphrase to be set in the device or empty.
    :param secondary_pin: Secondary PIN to activate passphrase. It's required if 'passphrase' is set.
    """
    def process(ctrl, mnemonic_words, pin, passphrase, secondary_pin):
        ctrl.dlg_config_fun(dlg_title="Please confirm",
                            show_progress_bar=False)
        ctrl.display_msg_fun('<b>Please wait while initializing device...</b>')

        dongle = getDongle()

        # stage 1: initialize the hardware wallet with mnemonic words
        apdudata = bytearray()
        if pin:
            apdudata += bytearray([len(pin)]) + bytearray(pin, 'utf8')
        else:
            apdudata += bytearray([0])

        # empty prefix
        apdudata += bytearray([0])

        # empty passphrase in this phase
        apdudata += bytearray([0])

        if mnemonic_words:
            apdudata += bytearray([len(mnemonic_words)]) + bytearray(
                mnemonic_words, 'utf8')
        else:
            apdudata += bytearray([0])

        apdu = bytearray([0xE0, 0xD0, 0x00, 0x00, len(apdudata)]) + apdudata
        dongle.exchange(apdu, timeout=3000)

        # stage 2: setup the secondary pin and the passphrase if provided
        if passphrase and secondary_pin:
            ctrl.display_msg_fun(
                '<b>Configuring the passphrase, enter the primary PIN on your <br>'
                'hardware wallet when asked...</b>')

            apdudata = bytearray()
            if pin:
                apdudata += bytearray([len(pin)]) + bytearray(
                    secondary_pin, 'utf8')
            else:
                apdudata += bytearray([0])

            # empty prefix
            apdudata += bytearray([0])

            if passphrase:
                passphrase = unicodedata.normalize('NFKD', passphrase)
                apdudata += bytearray([len(passphrase)]) + bytearray(
                    passphrase, 'utf8')
            else:
                apdudata += bytearray([0])

            # empty mnemonic words in this phase
            apdudata += bytearray([0])

            apdu = bytearray([0xE0, 0xD0, 0x01, 0x00,
                              len(apdudata)]) + apdudata
            dongle.exchange(apdu, timeout=3000)

        dongle.close()
        del dongle

    try:
        return WndUtils.run_thread_dialog(
            process, (mnemonic_words, pin, passphrase, secondary_pin), True)
    except BTChipException as e:
        if e.message == 'Invalid status 6982':
            raise Exception(
                'Operation failed with the following error: %s. \n\nMake sure you have reset the device '
                'and started it in recovery mode.' % e.message)
        else:
            raise
    except Exception as e:
        raise
Пример #19
0
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=DEFAULT_HW_BUSY_TITLE,
                                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
                from trezorlib import exceptions

                try:
                    if isinstance(bip32_path, str):
                        bip32_path = fix_utils.bip32_path_string_to_n(
                            bip32_path)
                    ret = btc.get_address(client,
                                          hw_session.app_config.hw_coin_name,
                                          bip32_path, show_display)
                    return ret
                except (CancelException, exceptions.Cancelled):
                    raise CancelException()

            elif hw_session.app_config.hw_type == HWType.keepkey:

                from keepkeylib.client import CallException

                try:
                    if isinstance(bip32_path, str):
                        bip32_path = fix_utils.bip32_path_string_to_n(
                            bip32_path)
                    return client.get_address(
                        hw_session.app_config.hw_coin_name, bip32_path,
                        show_display)
                except CallException as e:
                    if isinstance(e.args, tuple) and len(e.args) >= 2 and isinstance(e.args[1], str) and \
                            e.args[1].find('cancel') >= 0:
                        raise CancelException('Cancelled')

            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, show_display)
                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 message_to_display or show_display:
        msg_delay = 0
    else:
        msg_delay = 1000
        message_to_display = DEFAULT_HW_BUSY_MESSAGE

    return WndUtils.run_thread_dialog(
        _get_address,
        (hw_session, bip32_path, show_display, message_to_display),
        True,
        show_window_delay_ms=msg_delay,
        force_close_dlg_callback=partial(cancel_hw_thread_dialog,
                                         hw_session.hw_client))