コード例 #1
0
    def verify_connection(self, expected_xfp, expected_xpub):
        ex = (expected_xfp, expected_xpub)

        if self._expected_device == ex:
            # all is as expected
            return

        if ( (self._expected_device is not None) 
                or (self.dev.master_fingerprint != expected_xfp)
                or (self.dev.master_xpub != expected_xpub)):
            # probably indicating programing error, not hacking
            print_error("[coldcard]", f"xpubs. reported by device: {self.dev.master_xpub}. "
                                      f"stored in file: {expected_xpub}")
            raise RuntimeError("Expecting 0x%08x but that's not whats connected?!" %
                                    expected_xfp)

        # check signature over session key
        # - mitm might have lied about xfp and xpub up to here
        # - important that we use value capture at wallet creation time, not some value
        #   we read over USB today
        self.dev.check_mitm(expected_xpub=expected_xpub)

        self._expected_device = ex

        print_error("[coldcard]", "Successfully verified against MiTM")
コード例 #2
0
    def do_full_push(self):
        try:
            bundle = {"labels": {}}
            for key, value in self.wallet.labels.iteritems():
                encoded = self.encode(key)
                bundle["labels"][encoded] = self.encode(value)

            params = json.dumps(bundle)
            connection = httplib.HTTPConnection(self.target_host)
            connection.request(
                "POST", ("/api/wallets/%s/labels/batch.json?auth_token=%s" %
                         (self.wallet_id, self.auth_token())), params,
                {'Content-Type': 'application/json'})

            response = connection.getresponse()
            if response.reason == httplib.responses[httplib.NOT_FOUND]:
                return
            try:
                response = json.loads(response.read())
            except ValueError as e:
                return False

            if "error" in response:
                QMessageBox.warning(
                    None, _("Error"),
                    _("Could not sync labels: %s" % response["error"]))
                return False

            return True
        except socket.gaierror as e:
            print_error('Error connecting to service: %s ' % e)
            return False
コード例 #3
0
    def do_full_push(self):
        try:
            bundle = {"labels": {}}
            for key, value in self.wallet.labels.iteritems():
                encoded = self.encode(key)
                bundle["labels"][encoded] = self.encode(value)

            params = json.dumps(bundle)
            connection = httplib.HTTPConnection(self.target_host)
            connection.request("POST", ("/api/wallets/%s/labels/batch.json?auth_token=%s" % (self.wallet_id, self.auth_token())), params, {'Content-Type': 'application/json'})

            response = connection.getresponse()
            if response.reason == httplib.responses[httplib.NOT_FOUND]:
                return
            try:
                response = json.loads(response.read())
            except ValueError as e:
                return False

            if "error" in response:
                QMessageBox.warning(None, _("Error"),_("Could not sync labels: %s" % response["error"]))
                return False

            return True
        except socket.gaierror as e:
            print_error('Error connecting to service: %s ' %  e)
            return False
コード例 #4
0
    def do_full_pull(self, force = False):
        try:
            connection = httplib.HTTPConnection(self.target_host)
            connection.request("GET", ("/api/wallets/%s/labels.json?auth_token=%s" % (self.wallet_id, self.auth_token())),"", {'Content-Type': 'application/json'})
            response = connection.getresponse()
            if response.reason == httplib.responses[httplib.NOT_FOUND]:
                return
            try:
                response = json.loads(response.read())
            except ValueError as e:
                return False

            if "error" in response:
                QMessageBox.warning(None, _("Error"),_("Could not sync labels: %s" % response["error"]))
                return False

            for label in response:
                 decoded_key = self.decode(label["external_id"]) 
                 decoded_label = self.decode(label["text"]) 
                 if force or not self.wallet.labels.get(decoded_key):
                     self.wallet.labels[decoded_key] = decoded_label 
            return True
        except socket.gaierror as e:
            print_error('Error connecting to service: %s ' %  e)
            return False
コード例 #5
0
 def get_xpub(self, bip32_path):
     self.checkDevice()
     # bip32_path is of the form 44'/0'/1'
     # S-L-O-W - we don't handle the fingerprint directly, so compute
     # it manually from the previous node
     # This only happens once so it's bearable
     #self.get_client() # prompt for the PIN before displaying the dialog if necessary
     #self.handler.show_message("Computing master public key")
     try:
         splitPath = bip32_path.split('/')
         if splitPath[0] == 'm':
             splitPath = splitPath[1:]
             bip32_path = bip32_path[2:]
         fingerprint = 0
         if len(splitPath) > 1:
             prevPath = "/".join(splitPath[0:len(splitPath) - 1])
             nodeData = self.dongleObject.getWalletPublicKey(prevPath)
             publicKey = compress_public_key(nodeData['publicKey'])
             h = hashlib.new('ripemd160')
             h.update(hashlib.sha256(publicKey).digest())
             fingerprint = unpack(">I", h.digest()[0:4])[0]
         nodeData = self.dongleObject.getWalletPublicKey(bip32_path)
         publicKey = compress_public_key(nodeData['publicKey'])
         depth = len(splitPath)
         lastChild = splitPath[len(splitPath) - 1].split('\'')
         if len(lastChild) == 1:
             childnum = int(lastChild[0])
         else:
             childnum = 0x80000000 | int(lastChild[0])
         xpub = bitcoin.serialize_xpub(0, str(nodeData['chainCode']), str(publicKey), depth, self.i4b(fingerprint), self.i4b(childnum))
         return xpub
     except Exception as e:
         print_error(e)
         return None
コード例 #6
0
    def do_full_pull(self, force=False):
        try:
            connection = httplib.HTTPConnection(self.target_host)
            connection.request("GET",
                               ("/api/wallets/%s/labels.json?auth_token=%s" %
                                (self.wallet_id, self.auth_token())), "",
                               {'Content-Type': 'application/json'})
            response = connection.getresponse()
            if response.reason == httplib.responses[httplib.NOT_FOUND]:
                return
            try:
                response = json.loads(response.read())
            except ValueError as e:
                return False

            if "error" in response:
                QMessageBox.warning(
                    None, _("Error"),
                    _("Could not sync labels: %s" % response["error"]))
                return False

            for label in response:
                decoded_key = self.decode(label["external_id"])
                decoded_label = self.decode(label["text"])
                if force or not self.wallet.labels.get(decoded_key):
                    self.wallet.labels[decoded_key] = decoded_label
            return True
        except socket.gaierror as e:
            print_error('Error connecting to service: %s ' % e)
            return False
コード例 #7
0
ファイル: __init__.py プロジェクト: Vitalynx/vialectrum
    def start_new_window(self, path, uri):
        '''Raises the window for the wallet if it is open.  Otherwise
        opens the wallet and creates a new window for it'''
        try:
            wallet = self.daemon.load_wallet(path, None)
        except BaseException as e:
            traceback.print_exc(file=sys.stdout)
            d = QMessageBox(QMessageBox.Warning, _('Error'),
                            _('Cannot load wallet') + ' (1):\n' + str(e))
            d.exec_()
            return
        if not wallet:
            storage = WalletStorage(path, manual_upgrades=True)
            wizard = InstallWizard(self.config, self.app, self.plugins,
                                   storage)
            try:
                wallet = wizard.run_and_get_wallet(self.daemon.get_wallet)
            except UserCancelled:
                pass
            except GoBack as e:
                print_error('[start_new_window] Exception caught (GoBack)', e)
            except (WalletFileException, BitcoinException) as e:
                traceback.print_exc(file=sys.stderr)
                d = QMessageBox(QMessageBox.Warning, _('Error'),
                                _('Cannot load wallet') + ' (2):\n' + str(e))
                d.exec_()
                return
            finally:
                wizard.terminate()
            if not wallet:
                return

            if not self.daemon.get_wallet(wallet.storage.path):
                # wallet was not in memory
                wallet.start_threads(self.daemon.network)
                self.daemon.add_wallet(wallet)
        try:
            for w in self.windows:
                if w.wallet.storage.path == wallet.storage.path:
                    w.bring_to_top()
                    return
            w = self.create_window_for_wallet(wallet)
        except BaseException as e:
            traceback.print_exc(file=sys.stdout)
            d = QMessageBox(
                QMessageBox.Warning, _('Error'),
                _('Cannot create window for wallet') + ':\n' + str(e))
            d.exec_()
            return
        if uri:
            w.pay_to_URI(uri)
        w.bring_to_top()
        w.setWindowState(w.windowState() & ~QtCore.Qt.WindowMinimized
                         | QtCore.Qt.WindowActive)

        # this will activate the window
        w.activateWindow()
        return w
コード例 #8
0
 def give_error(self, message, clear_client=False):
     print_error(message)
     if not self.ux_busy:
         self.handler.show_error(message)
     else:
         self.ux_busy = False
     if clear_client:
         self.client = None
     raise UserFacingException(message)
コード例 #9
0
ファイル: ledger.py プロジェクト: Vitalynx/vialectrum
 def give_error(self, message, clear_client=False):
     print_error(message)
     if not self.signing:
         self.handler.show_error(message)
     else:
         self.signing = False
     if clear_client:
         self.client = None
     raise Exception(message)
コード例 #10
0
 def load_theme(self):
     """Load theme retrieved from wallet file."""
     try:
         theme_prefix, theme_path = self.themes[self.theme_name]
     except KeyError:
         util.print_error("Theme not found!", self.theme_name)
         return
     full_theme_path = "%s/%s/style.css" % (theme_prefix, theme_path)
     with open(full_theme_path) as style_file:
         qApp.setStyleSheet(style_file.read())
コード例 #11
0
 def get_xpub(self, bip32_path, xtype):
     assert xtype in ColdcardPlugin.SUPPORTED_XTYPES
     print_error('[coldcard]', 'Derive xtype = %r' % xtype)
     xpub = self.dev.send_recv(CCProtocolPacker.get_xpub(bip32_path), timeout=5000)
     # TODO handle timeout?
     # change type of xpub to the requested type
     try:
         node = BIP32Node.from_xkey(xpub)
     except InvalidMasterKeyVersionBytes:
         raise UserFacingException(_('Invalid xpub magic. Make sure your {} device is set to the correct chain.')
                                   .format(self.device)) from None
     if xtype != 'standard':
         xpub = node._replace(xtype=xtype).to_xpub()
     return xpub
コード例 #12
0
 def hid_send_plain(self, msg):
     reply = ""
     try:
         self.dbb_hid.write('\0' + bytearray(msg) + '\0' *
                            (self.hidBufSize - len(msg)))
         r = []
         while len(r) < self.hidBufSize:
             r = r + self.dbb_hid.read(self.hidBufSize)
         r = str(bytearray(r)).rstrip(' \t\r\n\0')
         r = r.replace("\0", '')
         reply = json.loads(r)
     except Exception as e:
         print_error('Exception caught ' + str(e))
     return reply
コード例 #13
0
 def hid_send_encrypt(self, msg):
     reply = ""
     try:
         secret = Hash(self.password)
         msg = EncodeAES(secret, msg)
         reply = self.hid_send_plain(msg)
         if 'ciphertext' in reply:
             reply = DecodeAES(secret, ''.join(reply["ciphertext"]))
             reply = json.loads(reply)
         if 'error' in reply:
             self.password = None
     except Exception as e:
         print_error('Exception caught ' + str(e))
     return reply
コード例 #14
0
ファイル: __init__.py プロジェクト: sotblad/vialectrum
 def set_dark_theme_if_needed(self):
     use_dark_theme = self.config.get('qt_gui_color_theme',
                                      'default') == 'dark'
     if use_dark_theme:
         try:
             import qdarkstyle
             self.app.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())
         except BaseException as e:
             use_dark_theme = False
             print_error('Error setting dark theme: {}'.format(e))
     # Even if we ourselves don't set the dark theme,
     # the OS/window manager/etc might set *a dark theme*.
     # Hence, try to choose colors accordingly:
     ColorScheme.update_from_widget(QWidget(), force_dark=use_dark_theme)
コード例 #15
0
    def set_label(self, item,label, changed):
        if not changed:
            return 
        try:
            bundle = {"label": {"external_id": self.encode(item), "text": self.encode(label)}}
            params = json.dumps(bundle)
            connection = httplib.HTTPConnection(self.target_host)
            connection.request("POST", ("/api/wallets/%s/labels.json?auth_token=%s" % (self.wallet_id, self.auth_token())), params, {'Content-Type': 'application/json'})

            response = connection.getresponse()
            if response.reason == httplib.responses[httplib.NOT_FOUND]:
                return
            response = json.loads(response.read())
        except socket.gaierror as e:
            print_error('Error connecting to service: %s ' %  e)
            return False
コード例 #16
0
    def sign_transaction(self, tx, password):
        # Build a PSBT in memory, upload it for signing.
        # - we can also work offline (without paired device present)
        if tx.is_complete():
            return

        client = self.get_client()

        assert client.dev.master_fingerprint == self.ckcc_xfp

        raw_psbt = self.build_psbt(tx)

        #open('debug.psbt', 'wb').write(out_fd.getvalue())

        try:
            try:
                self.handler.show_message("Authorize Transaction...")

                client.sign_transaction_start(raw_psbt, True)

                while 1:
                    # How to kill some time, without locking UI?
                    time.sleep(0.250)

                    resp = client.sign_transaction_poll()
                    if resp is not None:
                        break

                rlen, rsha = resp

                # download the resulting txn.
                new_raw = client.download_file(rlen, rsha)

            finally:
                self.handler.finished()

        except (CCUserRefused, CCBusyError) as exc:
            print_error('[coldcard]', 'Did not sign:', str(exc))
            self.handler.show_error(str(exc))
            return
        except BaseException as e:
            traceback.print_exc(file=sys.stderr)
            self.give_error(e, True)
            return

        # trust the coldcard to re-searilize final product right?
        tx.update(bh2u(new_raw))
コード例 #17
0
 def use_tor_proxy(self, use_it):
     if not use_it:
         self.proxy_cb.setChecked(False)
     else:
         socks5_mode_index = self.proxy_mode.findText('SOCKS5')
         if socks5_mode_index == -1:
             print_error("[network_dialog] can't find proxy_mode 'SOCKS5'")
             return
         self.proxy_mode.setCurrentIndex(socks5_mode_index)
         self.proxy_host.setText("127.0.0.1")
         self.proxy_port.setText(str(self.tor_proxy[1]))
         self.proxy_user.setText("")
         self.proxy_password.setText("")
         self.tor_cb.setChecked(True)
         self.proxy_cb.setChecked(True)
     self.check_disable_proxy(use_it)
     self.set_proxy()
コード例 #18
0
 def get_xpub(self, bip32_path, xtype):
     assert xtype in ColdcardPlugin.SUPPORTED_XTYPES
     print_error('[coldcard]', 'Derive xtype = %r' % xtype)
     xpub = self.dev.send_recv(CCProtocolPacker.get_xpub(bip32_path),
                               timeout=5000)
     # TODO handle timeout?
     # change type of xpub to the requested type
     try:
         __, depth, fingerprint, child_number, c, cK = deserialize_xpub(
             xpub)
     except InvalidMasterKeyVersionBytes:
         raise Exception(
             _('Invalid xpub magic. Make sure your {} device is set to the correct chain.'
               ).format(self.device)) from None
     if xtype != 'standard':
         xpub = serialize_xpub(xtype, c, cK, depth, fingerprint,
                               child_number)
     return xpub
コード例 #19
0
 def hid_send_plain(self, msg):
     reply = ""
     try:
         serial_number = self.dbb_hid.get_serial_number_string()
         if "v2.0." in serial_number or "v1." in serial_number:
             hidBufSize = 4096
             self.dbb_hid.write('\0' + msg + '\0' * (hidBufSize - len(msg)))
             r = bytearray()
             while len(r) < hidBufSize:
                 r += bytearray(self.dbb_hid.read(hidBufSize))
         else:
             self.hid_send_frame(msg)
             r = self.hid_read_frame()
         r = r.rstrip(b' \t\r\n\0')
         r = r.replace(b"\0", b'')
         r = to_string(r, 'utf8')
         reply = json.loads(r)
     except Exception as e:
         print_error('Exception caught ' + str(e))
     return reply
コード例 #20
0
    def set_label(self, item, label, changed):
        if not changed:
            return
        try:
            bundle = {
                "label": {
                    "external_id": self.encode(item),
                    "text": self.encode(label)
                }
            }
            params = json.dumps(bundle)
            connection = httplib.HTTPConnection(self.target_host)
            connection.request("POST",
                               ("/api/wallets/%s/labels.json?auth_token=%s" %
                                (self.wallet_id, self.auth_token())), params,
                               {'Content-Type': 'application/json'})

            response = connection.getresponse()
            if response.reason == httplib.responses[httplib.NOT_FOUND]:
                return
            response = json.loads(response.read())
        except socket.gaierror as e:
            print_error('Error connecting to service: %s ' % e)
            return False
コード例 #21
0
    def sign_transaction(self, tx, password):
        if tx.is_complete():
            return

        try:
            p2shTransaction = False
            derivations = self.get_tx_derivations(tx)
            hasharray = []
            pubkeyarray = []

            # Build hasharray from inputs
            for i, txin in enumerate(tx.inputs()):
                if txin['type'] == 'coinbase':
                    self.give_error(
                        "Coinbase not supported")  # should never happen

                if txin['type'] in ['p2sh']:
                    p2shTransaction = True

                for x_pubkey in txin['x_pubkeys']:
                    if x_pubkey in derivations:
                        index = derivations.get(x_pubkey)
                        inputPath = "%s/%d/%d" % (self.get_derivation(),
                                                  index[0], index[1])
                        inputHash = Hash(
                            tx.serialize_preimage(i).decode('hex')).encode(
                                'hex')
                        hasharray_i = {'hash': inputHash, 'keypath': inputPath}
                        hasharray.append(hasharray_i)
                        break
                else:
                    self.give_error("No matching x_key for sign_transaction"
                                    )  # should never happen

            # Sanity check
            if p2shTransaction:
                for txinput in tx.inputs():
                    if txinput['type'] != 'p2sh':
                        self.give_error(
                            "P2SH / regular input mixed in same transaction not supported"
                        )  # should never happen

            # Build pubkeyarray from outputs (unused because echo for smart verification not implemented)
            if not p2shTransaction:
                for _type, address, amount in tx.outputs():
                    assert _type == TYPE_ADDRESS
                    info = tx.output_info.get(address)
                    if info is not None:
                        index, xpubs, m = info
                        changePath = self.get_derivation() + "/%d/%d" % index
                        changePubkey = self.derive_pubkey(index[0], index[1])
                        pubkeyarray_i = {
                            'pubkey': changePubkey,
                            'keypath': changePath
                        }
                        pubkeyarray.append(pubkeyarray_i)

            # 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": {"meta":"%s", "data":%s, "checkpub":%s} }' % \
                       (Hash(tx.serialize()).encode('hex'), json.dumps(hashes), json.dumps(pubkeyarray))

                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 steps > 1:
                    self.handler.show_message(_("Signing large transaction. Please be patient ...\r\n\r\n" \
                                                "To continue, touch the Digital Bitbox's blinking light for 3 seconds. " \
                                                "(Touch " + str(step + 1) + " of " + str(int(steps)) + ")\r\n\r\n" \
                                                "To cancel, briefly touch the blinking light or wait for the timeout.\r\n\r\n"))
                else:
                    self.handler.show_message(_("Signing transaction ...\r\n\r\n" \
                                                "To continue, touch the Digital Bitbox's blinking light for 3 seconds.\r\n\r\n" \
                                                "To cancel, briefly touch the blinking light or wait for the timeout."))

                reply = dbb_client.hid_send_encrypt(
                    msg
                )  # Send twice, first returns an echo for smart verification (not implemented)
                self.handler.clear_dialog()

                if 'error' in reply:
                    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()):
                num = txin['num_sig']
                for pubkey in txin['pubkeys']:
                    signatures = filter(None, txin['signatures'])
                    if len(signatures) == num:
                        break  # txin is complete
                    ii = txin['pubkeys'].index(pubkey)
                    signed = dbb_signatures[i]
                    if signed['pubkey'] != pubkey:
                        continue
                    sig_r = int(signed['sig'][:64], 16)
                    sig_s = int(signed['sig'][64:], 16)
                    sig = sigencode_der(sig_r, sig_s,
                                        generator_secp256k1.order())
                    txin['signatures'][ii] = sig.encode('hex')
                    tx._inputs[i] = txin

        except BaseException as e:
            self.give_error(e, True)
        else:
            print_error("Transaction is_complete", tx.is_complete())
            tx.raw = tx.serialize()
コード例 #22
0
    def run(self, action):

        if action == 'new':
            action, wallet_type = self.restore_or_create()
            self.storage.put('wallet_type', wallet_type, False)

        if action is None:
            return

        if action == 'restore':
            wallet = self.restore(wallet_type)
            if not wallet:
                return
            action = None

        else:
            wallet = Wallet(self.storage)
            action = wallet.get_action()
            # fixme: password is only needed for multiple accounts
            password = None

        while action is not None:

            util.print_error("installwizard:", wallet, action)

            if action == 'create_seed':
                seed = wallet.make_seed()
                if not self.show_seed(seed, None):
                    return
                if not self.verify_seed(seed, None):
                    return
                password = self.password_dialog()
                wallet.add_seed(seed, password)

            elif action == 'add_cosigner':
                xpub_hot = wallet.master_public_keys.get("m/")
                r = self.multi_mpk_dialog(xpub_hot, 1)
                if not r:
                    return
                xpub_cold = r[0]
                wallet.add_master_public_key("cold/", xpub_cold)

            elif action == 'add_two_cosigners':
                xpub_hot = wallet.master_public_keys.get("m/")
                r = self.multi_mpk_dialog(xpub_hot, 2)
                if not r:
                    return
                xpub1, xpub2 = r
                wallet.add_master_public_key("cold/", xpub1)
                wallet.add_master_public_key("remote/", xpub2)

            elif action == 'create_accounts':
                wallet.create_accounts(password)
                self.waiting_dialog(wallet.synchronize)

            elif action == 'create_cold_seed':
                self.create_cold_seed(wallet)
                return

            else:
                 r = run_hook('install_wizard_action', self, wallet, action)
                 if not r: 
                     raise BaseException('unknown wizard action', action)

            # next action
            action = wallet.get_action()


        if self.network:
            if self.network.interfaces:
                self.network_dialog()
            else:
                QMessageBox.information(None, _('Warning'), _('You are offline'), _('OK'))
                self.network.stop()
                self.network = None

        # start wallet threads
        wallet.start_threads(self.network)

        if action == 'restore':
            self.waiting_dialog(lambda: wallet.restore(self.waiting_label.setText))
            if self.network:
                if wallet.is_found():
                    QMessageBox.information(None, _('Information'), _("Recovery successful"), _('OK'))
                else:
                    QMessageBox.information(None, _('Information'), _("No transactions found for this seed"), _('OK'))
            else:
                QMessageBox.information(None, _('Information'), _("This wallet was restored offline. It may contain more addresses than displayed."), _('OK'))

        return wallet
コード例 #23
0
    def sign_transaction(self, tx, password):
        if tx.is_complete():
            return

        try:
            p2pkhTransaction = True
            derivations = self.get_tx_derivations(tx)
            inputhasharray = []
            hasharray = []
            pubkeyarray = []

            # Build hasharray from inputs
            for i, txin in enumerate(tx.inputs()):
                if txin['type'] == 'coinbase':
                    self.give_error(
                        "Coinbase not supported")  # should never happen

                if txin['type'] != 'p2pkh':
                    p2pkhTransaction = False

                for x_pubkey in txin['x_pubkeys']:
                    if x_pubkey in derivations:
                        index = derivations.get(x_pubkey)
                        inputPath = "%s/%d/%d" % (self.get_derivation(),
                                                  index[0], index[1])
                        inputHash = Hash(
                            binascii.unhexlify(tx.serialize_preimage(i)))
                        hasharray_i = {
                            'hash': to_hexstr(inputHash),
                            'keypath': inputPath
                        }
                        hasharray.append(hasharray_i)
                        inputhasharray.append(inputHash)
                        break
                else:
                    self.give_error("No matching x_key for sign_transaction"
                                    )  # should never happen

            # Build pubkeyarray from outputs
            for _type, address, amount in tx.outputs():
                assert _type == TYPE_ADDRESS
                info = tx.output_info.get(address)
                if info is not None:
                    index, xpubs, m = info
                    changePath = self.get_derivation() + "/%d/%d" % index
                    changePubkey = self.derive_pubkey(index[0], index[1])
                    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:

                class CustomTXSerialization(Transaction):
                    @classmethod
                    def input_script(self, txin, estimate_size=False):
                        if txin['type'] == 'p2pkh':
                            return Transaction.get_preimage_script(txin)
                        if txin['type'] == 'p2sh':
                            # Multisig verification has partial support, but is disabled. This is the
                            # expected serialization though, so we leave it here until we activate it.
                            return '00' + push_script(
                                Transaction.get_preimage_script(txin))
                        raise Exception("unsupported type %s" % txin['type'])

                tx_dbb_serialized = CustomTXSerialization(
                    tx.serialize()).serialize()
            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(Hash(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 ...\r\n\r\n" \
                                                "To continue, touch the Digital Bitbox's blinking light for 3 seconds. " \
                                                "(Touch " + str(step + 1) + " of " + str(int(steps)) + ")\r\n\r\n" \
                                                "To cancel, briefly touch the blinking light or wait for the timeout.\r\n\r\n"))
                else:
                    self.handler.show_message(_("Signing transaction ...\r\n\r\n" \
                                                "To continue, touch the Digital Bitbox's blinking light for 3 seconds.\r\n\r\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()):
                num = txin['num_sig']
                for pubkey in txin['pubkeys']:
                    signatures = list(filter(None, txin['signatures']))
                    if len(signatures) == num:
                        break  # txin is complete
                    ii = txin['pubkeys'].index(pubkey)
                    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 = MyVerifyingKey.from_signature(s,
                                                           recid,
                                                           h,
                                                           curve=SECP256k1)
                        pk = to_hexstr(point_to_ser(pk.pubkey.point, True))
                    elif 'pubkey' in signed:
                        # firmware <= v2.1.1
                        pk = signed['pubkey']
                    if pk != pubkey:
                        continue
                    sig_r = int(signed['sig'][:64], 16)
                    sig_s = int(signed['sig'][64:], 16)
                    sig = sigencode_der(sig_r, sig_s,
                                        generator_secp256k1.order())
                    txin['signatures'][ii] = to_hexstr(sig) + '01'
                    tx._inputs[i] = txin
        except UserCancelled:
            raise
        except BaseException as e:
            self.give_error(e, True)
        else:
            print_error("Transaction is_complete", tx.is_complete())
            tx.raw = tx.serialize()
コード例 #24
0
 def update_status(self, b):
     print_error('trezor status', b)
コード例 #25
0
ファイル: cmdline.py プロジェクト: sotblad/vialectrum
 def update_status(self, b):
     print_error('hw device status', b)
コード例 #26
0
ファイル: cmdline.py プロジェクト: sotblad/vialectrum
 def show_error(self, msg, blocking=False):
     print_error(msg)
コード例 #27
0
    def run(self, action):

        if action == 'new':
            action, wallet_type = self.restore_or_create()
            self.storage.put('wallet_type', wallet_type, False)

        if action is None:
            return

        if action == 'restore':
            wallet = self.restore(wallet_type)
            if not wallet:
                return
            action = None

        else:
            wallet = Wallet(self.storage)
            action = wallet.get_action()
            # fixme: password is only needed for multiple accounts
            password = None

        while action is not None:

            util.print_error("installwizard:", wallet, action)

            if action == 'create_seed':
                seed = wallet.make_seed()
                if not self.show_seed(seed, None):
                    return
                if not self.verify_seed(seed, None):
                    return
                password = self.password_dialog()
                wallet.add_seed(seed, password)

            elif action == 'add_cosigner':
                xpub_hot = wallet.master_public_keys.get("m/")
                r = self.multi_mpk_dialog(xpub_hot, 1)
                if not r:
                    return
                xpub_cold = r[0]
                wallet.add_master_public_key("cold/", xpub_cold)

            elif action == 'add_two_cosigners':
                xpub_hot = wallet.master_public_keys.get("m/")
                r = self.multi_mpk_dialog(xpub_hot, 2)
                if not r:
                    return
                xpub1, xpub2 = r
                wallet.add_master_public_key("cold/", xpub1)
                wallet.add_master_public_key("remote/", xpub2)

            elif action == 'create_accounts':
                wallet.create_accounts(password)
                self.waiting_dialog(wallet.synchronize)

            elif action == 'create_cold_seed':
                self.create_cold_seed(wallet)
                return

            else:
                r = run_hook('install_wizard_action', self, wallet, action)
                if not r:
                    raise BaseException('unknown wizard action', action)

            # next action
            action = wallet.get_action()

        if self.network:
            if self.network.interfaces:
                self.network_dialog()
            else:
                QMessageBox.information(None, _('Warning'),
                                        _('You are offline'), _('OK'))
                self.network.stop()
                self.network = None

        # start wallet threads
        wallet.start_threads(self.network)

        if action == 'restore':
            self.waiting_dialog(
                lambda: wallet.restore(self.waiting_label.setText))
            if self.network:
                if wallet.is_found():
                    QMessageBox.information(None, _('Information'),
                                            _("Recovery successful"), _('OK'))
                else:
                    QMessageBox.information(
                        None, _('Information'),
                        _("No transactions found for this seed"), _('OK'))
            else:
                QMessageBox.information(
                    None, _('Information'),
                    _("This wallet was restored offline. It may contain more addresses than displayed."
                      ), _('OK'))

        return wallet
コード例 #28
0
import sys
import platform

from vialectrum.plugins import BasePlugin, hook
from vialectrum_gui.qt.util import WaitingDialog, EnterButton, WindowModalDialog
from vialectrum.util import print_msg, print_error
from vialectrum.i18n import _

from PyQt4.QtGui import *
from PyQt4.QtCore import *

try:
    import amodem.audio
    import amodem.main
    import amodem.config
    print_error('Audio MODEM is available.')
    amodem.log.addHandler(amodem.logging.StreamHandler(sys.stderr))
    amodem.log.setLevel(amodem.logging.INFO)
except ImportError:
    amodem = None
    print_error('Audio MODEM is not found.')


class Plugin(BasePlugin):
    def __init__(self, parent, config, name):
        BasePlugin.__init__(self, parent, config, name)
        if self.is_available():
            self.modem_config = amodem.config.slowest()
            self.library_name = {'Linux': 'libportaudio.so'}[platform.system()]

    def is_available(self):
コード例 #29
0
ファイル: history_list.py プロジェクト: lavajumper/vialectrum
from vialectrum.util import (block_explorer_URL, profiler, print_error,
                             TxMinedInfo, OrderedDictWithIndex, PrintError,
                             timestamp_to_datetime)

from .util import (read_QIcon, MONOSPACE_FONT, Buttons, CancelButton, OkButton,
                   filename_field, MyTreeView, AcceptFileDragDrop,
                   WindowModalDialog, CloseButton)

if TYPE_CHECKING:
    from vialectrum.wallet import Abstract_Wallet

try:
    from vialectrum.plot import plot_history, NothingToPlotException
except:
    print_error(
        "qt/history_list: could not import vialectrum.plot. This feature needs matplotlib to be installed."
    )
    plot_history = None

# note: this list needs to be kept in sync with another in kivy
TX_ICONS = [
    "unconfirmed.png",
    "warning.png",
    "unconfirmed.png",
    "offline_tx.png",
    "clock1.png",
    "clock2.png",
    "clock3.png",
    "clock4.png",
    "clock5.png",
    "confirmed.png",