예제 #1
0
    def on_update(self):
        item = self.currentItem()
        current_tx, current_i = item.data(0, Qt.UserRole) if item else (None,
                                                                        None)
        self.clear()

        wallet = self.parent.wallet
        pmw = self.parent.pmw
        key = self.parent.key
        mypubkey = key.pubkey
        myaddress = key.address

        # internal function to be called within loop below
        def putitem(i, typ, datastr):
            if to_me:
                to_str = 'me'
            elif to_pubkey:
                to_str = to_pubkey[-3:].hex()
            else:
                to_str = 'unk'
            item = SortableTreeWidgetItem([
                '',
                status_str,
                'me' if from_me else from_pubkey[-3:].hex(),
                to_str,
                typ,
                datastr,
            ])

            if status not in self.statusIcons:
                self.statusIcons[status] = QIcon(":icons/" + TX_ICONS[status])
            icon = self.statusIcons[status]
            item.setIcon(0, icon)
            item.setData(0, SortableTreeWidgetItem.DataRole, (status, conf))
            item.setToolTip(
                0,
                str(conf) + " confirmation" + ("s" if conf != 1 else ""))

            item.setData(0, Qt.UserRole, (tx_hash, i))
            item.setData(2, Qt.UserRole, from_pubkey)
            item.setData(3, Qt.UserRole, to_pubkey)
            item.setToolTip(5, '<p>%s</p>' % (escape(datastr), ))
            self.insertTopLevelItem(0, item)
            if current_tx == tx_hash and current_i == i:
                self.setCurrentItem(item)
            return item

        for tx_hash, height in wallet.get_address_history(myaddress):
            info = pmw.messageinfo.get(tx_hash)
            if not info:
                continue
            height, conf, timestamp = wallet.get_tx_height(tx_hash)
            status, status_str = wallet.get_tx_status(tx_hash, height, conf,
                                                      timestamp)

            from_pubkey = info['src']
            dest_addr = info['dst']
            from_me = (from_pubkey == mypubkey)
            to_me = (dest_addr == myaddress)

            if to_me:
                to_pubkey = mypubkey
            else:
                to_pubkey = pmw.known_pubkeys.get(dest_addr)

            if info['status'] == 'processing':
                # tx needs to be verified
                putitem(0, '-', 'verifying')
                continue

            messagebytes = info.get('message')

            if messagebytes is None:
                putitem(0, '?', '')
                continue

            try:
                osm = openswap.OpenSwapMessage.from_bytes(messagebytes)
            except Exception as e:
                try:
                    message = repr(messagebytes.decode('utf8'))
                except:
                    message = messagebytes.hex()
                putitem(0, 'raw', "raw: " + message)
                continue
            for i, pak in enumerate(osm.packets):
                if isinstance(pak, openswap.PacketPad):  # skip padding
                    continue
                if isinstance(pak, openswap.PacketOffer) and not from_me:
                    # save incoming offer packets
                    self.incoming_offers[(from_pubkey, pak.offer_info)] = pak
                try:
                    datastr = pak.to_ui_string()
                except Exception as e:
                    print(e)
                    datastr = str(pak)
                if isinstance(pak, openswap.PacketOffer):
                    remain = pak.expire_time - time.time()
                    if remain > 0:
                        expstr = _("%d minutes remain") % (round(remain / 60.))
                    else:
                        expstr = _("expired")
                    if from_me:
                        fmtstr = _('You offer %s%s to get %s%s (%s)')
                    else:
                        fmtstr = _('They offer %s%s to get %s%s (%s)')
                    datastr = fmtstr % (
                        format_satoshis_plain_nofloat(
                            pak.offer_info.give_amount),
                        pak.offer_info.give_ticker.decode('utf8'),
                        format_satoshis_plain_nofloat(
                            pak.offer_info.want_amount),
                        pak.offer_info.want_ticker.decode('utf8'),
                        expstr,
                    )

                item = putitem(i, 'OS', datastr)
                item.setData(5, Qt.UserRole, pak)
예제 #2
0
 def notify_timedout(self, i):
     self.update_table_cb(i, _('Timed out'))
예제 #3
0
파일: ledger.py 프로젝트: proteanx/DeLight
from electroncash.util import print_error, is_verbose, bfh, bh2u, versiontuple

try:
    import hid
    from btchip.btchipComm import HIDDongleHIDAPI, DongleWait
    from btchip.btchip import btchip
    from btchip.btchipUtils import compress_public_key, format_transaction, get_regular_input_script, get_p2sh_input_script
    from btchip.bitcoinTransaction import bitcoinTransaction
    from btchip.btchipFirmwareWizard import checkFirmware, updateFirmware
    from btchip.btchipException import BTChipException
    BTCHIP = True
    BTCHIP_DEBUG = is_verbose
except ImportError:
    BTCHIP = False

MSG_NEEDS_FW_UPDATE_CASHADDR = _('Firmware version (or "Bitcoin Cash" app) too old for CashAddr support. ') + \
                               _('Please update at https://www.ledgerwallet.com')
MSG_NEEDS_SW_UPDATE_CASHADDR = _('python-btchip is too old for CashAddr support. ') + \
                               _('Please update to v0.1.27 or greater')
BITCOIN_CASH_SUPPORT_HW1 = (1, 0, 4)
BITCOIN_CASH_SUPPORT = (1, 1, 8)
CASHADDR_SUPPORT = (1, 2, 5)
MULTI_OUTPUT_SUPPORT = (1, 1, 4)


def test_pin_unlocked(func):
    """Function decorator to test the Ledger for being unlocked, and if not,
    raise a human-readable exception.
    """
    def catch_exception(self, *args, **kwargs):
        try:
예제 #4
0
    def run_and_get_wallet(self):

        vbox = QVBoxLayout()
        hbox = QHBoxLayout()
        hbox.addWidget(QLabel(_('Wallet') + ':'))
        self.name_e = QLineEdit()
        hbox.addWidget(self.name_e)
        button = QPushButton(_('Choose...'))
        hbox.addWidget(button)
        vbox.addLayout(hbox)

        self.msg_label = QLabel('')
        vbox.addWidget(self.msg_label)
        hbox2 = QHBoxLayout()
        self.pw_e = QLineEdit('', self)
        self.pw_e.setFixedWidth(150)
        self.pw_e.setEchoMode(2)
        self.pw_label = QLabel(_('Password') + ':')
        hbox2.addWidget(self.pw_label)
        hbox2.addWidget(self.pw_e)
        hbox2.addStretch()
        vbox.addLayout(hbox2)
        self.set_layout(vbox, title=_(f'{PROJECT_NAME} wallet'))

        wallet_folder = os.path.dirname(self.storage.path)

        def on_choose():
            path, __ = QFileDialog.getOpenFileName(self,
                                                   "Select your wallet file",
                                                   wallet_folder)
            if path:
                self.name_e.setText(path)

        def on_filename(filename):
            path = os.path.join(wallet_folder, filename)
            try:
                self.storage = WalletStorage(path, manual_upgrades=True)
                self.next_button.setEnabled(True)
            except IOError:
                self.storage = None
                self.next_button.setEnabled(False)
            if self.storage:
                if not self.storage.file_exists():
                    msg =_("This file does not exist.") + '\n' \
                          + _("Press 'Next' to create this wallet, or choose another file.")
                    pw = False
                elif self.storage.file_exists() and self.storage.is_encrypted(
                ):
                    msg = _("This file is encrypted.") + '\n' + _(
                        'Enter your password or choose another file.')
                    pw = True
                else:
                    msg = _("Press 'Next' to open this wallet.")
                    pw = False
            else:
                msg = _('Cannot read file')
                pw = False
            self.msg_label.setText(msg)
            if pw:
                self.pw_label.show()
                self.pw_e.show()
                self.pw_e.setFocus()
            else:
                self.pw_label.hide()
                self.pw_e.hide()

        button.clicked.connect(on_choose)
        self.name_e.textChanged.connect(on_filename)
        n = os.path.basename(self.storage.path)
        self.name_e.setText(n)

        while True:
            password = None
            if self.storage.file_exists() and not self.storage.is_encrypted():
                break
            if self.loop.exec_() != 2:  # 2 = next
                return
            if not self.storage.file_exists():
                break
            if self.storage.file_exists() and self.storage.is_encrypted():
                password = self.pw_e.text()
                try:
                    self.storage.decrypt(password)
                    break
                except InvalidPassword as e:
                    QMessageBox.information(None, _('Error'), str(e))
                    continue
                except BaseException as e:
                    traceback.print_exc(file=sys.stdout)
                    QMessageBox.information(None, _('Error'), str(e))
                    return

        path = self.storage.path
        if self.storage.requires_split():
            self.hide()
            msg = _(
                "The wallet '{}' contains multiple accounts, which are no longer supported since Electrum 2.7.\n\n"
                "Do you want to split your wallet into multiple files?"
            ).format(path)
            if not self.question(msg):
                return
            file_list = '\n'.join(self.storage.split_accounts())
            msg = _('Your accounts have been moved to'
                    ) + ':\n' + file_list + '\n\n' + _(
                        'Do you want to delete the old file') + ':\n' + path
            if self.question(msg):
                os.remove(path)
                self.show_warning(_('The file was removed'))
            return

        if self.storage.requires_upgrade():
            self.hide()
            msg = _(f"The format of your wallet {path} must be upgraded for "
                    f"{PROJECT_NAME}. This change will not be backward "
                    f"compatible")
            if not self.question(msg):
                return
            self.storage.upgrade()
            self.wallet = Wallet(self.storage)
            return self.wallet, password

        action = self.storage.get_action()
        if action and action != 'new':
            self.hide()
            msg = _("The file '{}' contains an incompletely created wallet.\n"
                    "Do you want to complete its creation now?").format(path)
            if not self.question(msg):
                if self.question(
                        _("Do you want to delete '{}'?").format(path)):
                    os.remove(path)
                    self.show_warning(_('The file was removed'))
                return
            self.show()
        if action:
            # self.wallet is set in run
            self.run(action)
            return self.wallet, password

        self.wallet = Wallet(self.storage)
        return self.wallet, password
예제 #5
0
 def on_n(n):
     n_label.setText(_('From %d cosigners') % n)
     cw.set_n(n)
     m_edit.setMaximum(n)
예제 #6
0
    def __init__(self, plugin_dialog, main_window, title, plugin_path=None, plugin_metadata=None):
        WindowModalDialog.__init__(self, parent=main_window.top_level_window(), title=title)

        self.is_preview = plugin_metadata is None

        self.main_window = main_window
        self.plugin_dialog = plugin_dialog

        self.setMinimumWidth(600)
        #self.setMaximumWidth(600)

        vbox = QVBoxLayout()
        self.setLayout(vbox)

        groupBox = QGroupBox(_("Plugin Metadata"))
        self.metadataFormLayout = QFormLayout(groupBox)
        self.metadataFormLayout.setFieldGrowthPolicy(QFormLayout.AllNonFixedFieldsGrow)
        self.pluginNameLabel = QLabel()
        self.metadataFormLayout.addRow(_("Name"), self.pluginNameLabel)
        self.versionLabel = QLabel()
        self.metadataFormLayout.addRow(_("Version"), self.versionLabel)
        self.projectUrlLabel = QLabel()
        self.projectUrlLabel.setToolTip(_("Click to open in web browser"))
        self.metadataFormLayout.addRow(_("Project URL"), self.projectUrlLabel)
        self.descriptionLabel = QLabel()
        self.descriptionLabel.setWordWrap(True)
        # Long description labels that wrap should push the form layout's row to grow
        p = self.descriptionLabel.sizePolicy(); p.setVerticalPolicy(QSizePolicy.MinimumExpanding); self.descriptionLabel.setSizePolicy(p)
        self.metadataFormLayout.addRow(_("Description"), self.descriptionLabel)
        self.supportedInterfacesLayout = QVBoxLayout()
        self.supportedInterfacesLabel = QLabel(_("Integration"))
        self.supportedInterfacesLabel.setAlignment(Qt.AlignLeft | Qt.AlignTop)
        self.supportedInterfacesLabel.setToolTip(_("Plugins should support one or more of these interfaces."))
        self.metadataFormLayout.addRow(self.supportedInterfacesLabel, self.supportedInterfacesLayout)

        self.qtInterfaceLabel = QLabel()
        self.qtInterfaceLabel.setMaximumWidth(20)
        row = QHBoxLayout()
        row.addWidget(self.qtInterfaceLabel)
        row.addWidget(QLabel(_("User interface.")))
        self.supportedInterfacesLayout.addLayout(row)

        self.cmdLineInterfaceLabel = QLabel()
        self.cmdLineInterfaceLabel.setMaximumWidth(20)
        row = QHBoxLayout()
        row.addWidget(self.cmdLineInterfaceLabel)
        row.addWidget(QLabel(_("Command-line.")))
        self.supportedInterfacesLayout.addLayout(row)

        self.checksumLabel = QLabel()
        self.checksumLabel.setToolTip(_("If the official source for this plugin has a checksum for this plugin, ensure that the value shown here is the same."))
        self.checksumLabel.setTextInteractionFlags(Qt.TextSelectableByMouse)
        self.metadataFormLayout.addRow(_("SHA256 Checksum"), self.checksumLabel)

        vbox.addWidget(groupBox,3)

        if self.is_preview:
            confirmLayout = QVBoxLayout()
            confirmLayout.setAlignment(Qt.AlignHCenter)
            confirmGroupBox = QGroupBox(_("Risks and Dangers"))
            liabilityLabel = QLabel(_("I accept responsibility for any harm that comes from installing this plugin, and acknowledge:"))
            rows = QVBoxLayout()
            self.liabilityCheckbox1 = QCheckBox(_("The Electron Cash Developers do NOT audit or vet any plugins."))
            self.liabilityCheckbox2 = QCheckBox(_("Plugins are risky.  They can steal funds or even damage your computer."))
            self.liabilityCheckbox3 = QCheckBox(_("I should only install the most reputable plugins trusted by the community."))
            confirmLayout.addWidget(liabilityLabel)
            confirmLayout.addWidget(self.liabilityCheckbox1)
            confirmLayout.addWidget(self.liabilityCheckbox2)
            confirmLayout.addWidget(self.liabilityCheckbox3)
            confirmGroupBox.setLayout(confirmLayout)
            vbox.addWidget(confirmGroupBox)

            hbox = QHBoxLayout()
            vbox.addLayout(hbox)
            self.installButton = QPushButton("Install")
            self.cancelButton = QPushButton("Close")
            self.cancelButton.setDefault(True)
            if sys.platform == 'darwin':
                # macOS convention is Cancel-on-left, "Action" on right
                hbox.addWidget(self.cancelButton)
                hbox.addStretch(1)
                hbox.addWidget(self.installButton)
            else:
                # non-macOS, go with the Windows convention of Cancel-on-right
                hbox.addWidget(self.installButton)
                hbox.addStretch(1)
                hbox.addWidget(self.cancelButton)

            self.installButton.clicked.connect(self.on_install)
            self.cancelButton.clicked.connect(self.close)
            self.liabilityCheckbox1.clicked.connect(self.on_liability_toggled)
            self.liabilityCheckbox2.clicked.connect(self.on_liability_toggled)
            self.liabilityCheckbox3.clicked.connect(self.on_liability_toggled)
        else:
            hbox = QHBoxLayout()
            vbox.addLayout(hbox)
            self.cancelButton = QPushButton("Close")
            self.cancelButton.setDefault(True)
            hbox.addStretch(1)
            hbox.addWidget(self.cancelButton)

            self.cancelButton.clicked.connect(self.close)

        self.pluginNameLabel.setText(_("Unavailable."))
        self.projectUrlLabel.setText(_("Unavailable."))
        self.versionLabel.setText(_("Unavailable."))
        self.descriptionLabel.setText(_("Unavailable."))
        self.checksumLabel.setText(_("Unavailable."))

        if plugin_path is not None:
            self.refresh_plugin_from_path(plugin_path)
        elif plugin_metadata is not None:
            self.refresh_plugin_from_metadata(plugin_metadata)
        self.refresh_ui()
예제 #7
0
    def on_update(self):
        if self.cleaned_up:
            return
        item = self.currentItem()
        current_contact = item.data(0,
                                    self.DataRoles.Contact) if item else None
        selected = self.selectedItems() or []
        selected_contacts = set(
            item.data(0, self.DataRoles.Contact) for item in selected)
        del item, selected  # must not hold a reference to a C++ object that will soon be deleted in self.clear()..
        self.clear()
        type_names = defaultdict(lambda: _("Unknown"))
        type_names.update({
            'openalias': _('OpenAlias'),
            'cashacct': _('Cash Account'),
            'cashacct_W': _('Cash Account') + ' [' + _('Mine') + ']',
            'cashacct_T': _('Cash Account') + ' [' + _('Pend') + ']',
            'address': _('Address'),
        })
        type_icons = {
            'openalias': self.icon_openalias,
            'cashacct': self.icon_cashacct,
            'cashacct_W': self.icon_cashacct,
            'cashacct_T': self.icon_unverif,
            'address': self.icon_contacts,
        }
        selected_items, current_item = [], None
        edited = self._edited_item_cur_sel
        for contact in self.get_full_contacts(
                include_pseudo=self.show_my_cashaccts):
            _type, name, address = contact.type, contact.name, contact.address
            label_key = address
            if _type in ('cashacct', 'cashacct_W', 'cashacct_T', 'address'):
                try:
                    # try and re-parse and re-display the address based on current UI string settings
                    addy = Address.from_string(address)
                    address = addy.to_ui_string()
                    label_key = addy.to_storage_string()
                    del addy
                except:
                    ''' This may happen because we may not have always enforced this as strictly as we could have in legacy code. Just move on.. '''
            label = self.wallet.get_label(label_key)
            item = QTreeWidgetItem(
                ["", name, label, address, type_names[_type]])
            item.setData(0, self.DataRoles.Contact, contact)
            item.DataRole = self.DataRoles.Contact
            if _type in ('cashacct', 'cashacct_W', 'cashacct_T'):
                ca_info = self.wallet.cashacct.get_verified(name)
                tt_warn = None
                if ca_info:
                    if self.wallet.is_mine(
                            ca_info.address) and not self.show_my_cashaccts:
                        # user may have added the contact to "self" manually
                        # but since they asked to not see their own cashaccts,
                        # we must do this to suppress it from being shown regardless
                        continue
                    item.setText(0, ca_info.emoji)
                    tt = _(
                        'Validated Cash Account: <b><pre>{emoji} {account_string}</pre></b>'
                    ).format(
                        emoji=ca_info.emoji,
                        account_string=
                        f'{ca_info.name}#{ca_info.number}.{ca_info.collision_hash};'
                    )
                else:
                    item.setIcon(0, self.icon_unverif)
                    if _type == 'cashacct_T':
                        tt_warn = tt = _(
                            'Cash Account pending confirmation and/or verification'
                        )
                    else:
                        tt_warn = tt = _(
                            'Warning: This Cash Account is not verified')
                item.setToolTip(0, tt)
                if tt_warn: item.setToolTip(1, tt_warn)
            if _type in type_icons:
                item.setIcon(4, type_icons[_type])
            # always give the "Address" field a monospace font even if it's
            # not strictly an address such as openalias...
            item.setFont(3, self.monospace_font)
            self.addTopLevelItem(item)
            if contact == current_contact or (contact == edited[0]
                                              and edited[1]):
                current_item = item  # this key was the current item before and it hasn't gone away
            if contact in selected_contacts or (contact == edited[0]
                                                and edited[2]):
                selected_items.append(
                    item
                )  # this key was selected before and it hasn't gone away

        if selected_items:  # sometimes currentItem is set even if nothing actually selected. grr..
            # restore current item & selections
            if current_item:
                # set the current item. this may also implicitly select it
                self.setCurrentItem(current_item)
            for item in selected_items:
                # restore the previous selection
                item.setSelected(True)
        self._edited_item_cur_sel = (None, ) * 3
        run_hook('update_contacts_tab', self)
예제 #8
0
 def __init__(self, parent):
     QTreeWidget.__init__(self)
     self.parent = parent
     self.setHeaderLabels(['', _('Host'), _('Port')])
     self.setContextMenuPolicy(Qt.CustomContextMenu)
     self.customContextMenuRequested.connect(self.create_menu)
예제 #9
0
    def __init__(self, parent, network, config, wizard=False):
        super().__init__(parent)
        self.network = network
        self.config = config
        self.protocol = None
        self.tor_proxy = None

        # tor detector
        self.td = TorDetector(self)
        self.td.found_proxy.connect(self.suggest_proxy)

        self.tabs = tabs = QTabWidget()
        server_tab = QWidget()
        weakTd = Weak.ref(self.td)

        class ProxyTab(QWidget):
            def showEvent(slf, e):
                super().showEvent(e)
                td = weakTd()
                if e.isAccepted() and td:
                    td.start(
                    )  # starts the tor detector when proxy_tab appears

            def hideEvent(slf, e):
                super().hideEvent(e)
                td = weakTd()
                if e.isAccepted() and td:
                    td.stop(
                    )  # stops the tor detector when proxy_tab disappears

        proxy_tab = ProxyTab()
        blockchain_tab = QWidget()
        tabs.addTab(blockchain_tab, _('Overview'))
        tabs.addTab(server_tab, _('Server'))
        tabs.addTab(proxy_tab, _('Proxy'))

        if wizard:
            tabs.setCurrentIndex(1)

        # server tab
        grid = QGridLayout(server_tab)
        grid.setSpacing(8)

        self.server_host = QLineEdit()
        self.server_host.setFixedWidth(200)
        self.server_port = QLineEdit()
        self.server_port.setFixedWidth(60)
        self.ssl_cb = QCheckBox(_('Use SSL'))
        self.autoconnect_cb = QCheckBox(_('Select server automatically'))
        self.autoconnect_cb.setEnabled(
            self.config.is_modifiable('auto_connect'))

        weakSelf = Weak.ref(
            self
        )  # Qt/Python GC hygeine: avoid strong references to self in lambda slots.
        self.server_host.editingFinished.connect(
            lambda: weakSelf() and weakSelf().set_server(onion_hack=True))
        self.server_port.editingFinished.connect(
            lambda: weakSelf() and weakSelf().set_server(onion_hack=True))
        self.ssl_cb.clicked.connect(self.change_protocol)
        self.autoconnect_cb.clicked.connect(self.set_server)
        self.autoconnect_cb.clicked.connect(self.update)

        msg = ' '.join([
            _("If auto-connect is enabled, Electron Cash will always use a server that is on the longest blockchain."
              ),
            _("If it is disabled, you have to choose a server you want to use. Electron Cash will warn you if your server is lagging."
              )
        ])
        grid.addWidget(self.autoconnect_cb, 0, 0, 1, 3)
        grid.addWidget(HelpButton(msg), 0, 4)

        self.preferred_only_cb = QCheckBox(
            _("Connect only to preferred servers"))
        self.preferred_only_cb.setEnabled(
            self.config.is_modifiable('whitelist_servers_only'))
        self.preferred_only_cb.setToolTip(
            _("If enabled, restricts Electron Cash to connecting to servers only marked as 'preferred'."
              ))

        self.preferred_only_cb.clicked.connect(
            self.set_whitelisted_only
        )  # re-set the config key and notify network.py

        msg = '\n\n'.join([
            _("If 'Connect only to preferred servers' is enabled, Electron Cash will only connect to servers marked as 'preferred' servers ({})."
              ).format(ServerFlag.Symbol[ServerFlag.Preferred]),
            _("This feature was added in response to the potential for a malicious actor to deny service via launching many servers (aka a sybil attack)."
              ),
            _("If unsure, most of the time it's safe to leave this option disabled. However leaving it enabled is safer (if a little bit discouraging to new server operators wanting to populate their servers)."
              )
        ])
        grid.addWidget(self.preferred_only_cb, 1, 0, 1, 3)
        grid.addWidget(HelpButton(msg), 1, 4)

        grid.addWidget(self.ssl_cb, 2, 0, 1, 3)
        self.ssl_help = HelpButton(
            _('SSL is used to authenticate and encrypt your connections with the blockchain servers.'
              ) + "\n\n" +
            _('Due to potential security risks, you may only disable SSL when using a Tor Proxy.'
              ))
        grid.addWidget(self.ssl_help, 2, 4)

        grid.addWidget(QLabel(_('Server') + ':'), 3, 0)
        grid.addWidget(self.server_host, 3, 1, 1, 2)
        grid.addWidget(self.server_port, 3, 3)

        self.server_list_label = label = QLabel(
            '')  # will get set by self.update()
        grid.addWidget(label, 4, 0, 1, 5)
        self.servers_list = ServerListWidget(self)
        grid.addWidget(self.servers_list, 5, 0, 1, 5)
        self.legend_label = label = WWLabel(
            '')  # will get populated with the legend by self.update()
        label.setTextInteractionFlags(label.textInteractionFlags() & (
            ~Qt.TextSelectableByMouse))  # disable text selection by mouse here
        self.legend_label.linkActivated.connect(self.on_view_blacklist)
        grid.addWidget(label, 6, 0, 1, 4)
        msg = ' '.join([
            _("Preferred servers ({}) are servers you have designated as reliable and/or trustworthy."
              ).format(ServerFlag.Symbol[ServerFlag.Preferred]),
            _("Initially, the preferred list is the hard-coded list of known-good servers vetted by the Electron Cash developers."
              ),
            _("You can add or remove any server from this list and optionally elect to only connect to preferred servers."
              ), "\n\n" +
            _("Banned servers ({}) are servers deemed unreliable and/or untrustworthy, and so they will never be connected-to by Electron Cash."
              ).format(ServerFlag.Symbol[ServerFlag.Banned])
        ])
        grid.addWidget(HelpButton(msg), 6, 4)

        # Proxy tab
        grid = QGridLayout(proxy_tab)
        grid.setSpacing(8)

        # proxy setting
        self.proxy_cb = QCheckBox(_('Use proxy'))
        self.proxy_cb.clicked.connect(self.check_disable_proxy)
        self.proxy_cb.clicked.connect(self.set_proxy)

        self.proxy_mode = QComboBox()
        self.proxy_mode.addItems(['SOCKS4', 'SOCKS5', 'HTTP'])
        self.proxy_host = QLineEdit()
        self.proxy_host.setFixedWidth(200)
        self.proxy_port = QLineEdit()
        self.proxy_port.setFixedWidth(60)
        self.proxy_user = QLineEdit()
        self.proxy_user.setPlaceholderText(_("Proxy user"))
        self.proxy_password = QLineEdit()
        self.proxy_password.setPlaceholderText(_("Password"))
        self.proxy_password.setEchoMode(QLineEdit.Password)
        self.proxy_password.setFixedWidth(60)

        self.proxy_mode.currentIndexChanged.connect(self.set_proxy)
        self.proxy_host.editingFinished.connect(self.set_proxy)
        self.proxy_port.editingFinished.connect(self.set_proxy)
        self.proxy_user.editingFinished.connect(self.set_proxy)
        self.proxy_password.editingFinished.connect(self.set_proxy)

        self.proxy_mode.currentIndexChanged.connect(
            self.proxy_settings_changed)
        self.proxy_host.textEdited.connect(self.proxy_settings_changed)
        self.proxy_port.textEdited.connect(self.proxy_settings_changed)
        self.proxy_user.textEdited.connect(self.proxy_settings_changed)
        self.proxy_password.textEdited.connect(self.proxy_settings_changed)

        self.tor_cb = QCheckBox(_("Use Tor Proxy"))
        self.tor_cb.setIcon(QIcon(":icons/tor_logo.svg"))
        self.tor_cb.setEnabled(False)
        self.tor_cb.clicked.connect(self.use_tor_proxy)

        grid.addWidget(self.tor_cb, 1, 0, 1, 3)
        grid.addWidget(self.proxy_cb, 2, 0, 1, 3)
        grid.addWidget(
            HelpButton(
                _('Proxy settings apply to all connections: with Electron Cash servers, but also with third-party services.'
                  )), 2, 4)
        grid.addWidget(self.proxy_mode, 4, 1)
        grid.addWidget(self.proxy_host, 4, 2)
        grid.addWidget(self.proxy_port, 4, 3)
        grid.addWidget(self.proxy_user, 5, 2)
        grid.addWidget(self.proxy_password, 5, 3)
        grid.setRowStretch(7, 1)

        # Blockchain Tab
        grid = QGridLayout(blockchain_tab)
        msg = ' '.join([
            _("DeLight connects to several nodes in order to download block headers and find out the longest blockchain."
              ),
            _("This blockchain is used to verify the transactions sent by your transaction server."
              )
        ])
        self.status_label = QLabel('')
        self.status_label.setTextInteractionFlags(
            self.status_label.textInteractionFlags()
            | Qt.TextSelectableByMouse)
        grid.addWidget(QLabel(_('Status') + ':'), 0, 0)
        grid.addWidget(self.status_label, 0, 1, 1, 3)
        grid.addWidget(HelpButton(msg), 0, 4)

        self.server_label = QLabel('')
        self.server_label.setTextInteractionFlags(
            self.server_label.textInteractionFlags()
            | Qt.TextSelectableByMouse)
        msg = _(
            "DeLight sends your wallet addresses to a single server, in order to receive your transaction history."
        )
        grid.addWidget(QLabel(_('Server') + ':'), 1, 0)
        grid.addWidget(self.server_label, 1, 1, 1, 3)
        grid.addWidget(HelpButton(msg), 1, 4)

        self.height_label = QLabel('')
        self.height_label.setTextInteractionFlags(
            self.height_label.textInteractionFlags()
            | Qt.TextSelectableByMouse)
        msg = _('This is the height of your local copy of the blockchain.')
        grid.addWidget(QLabel(_('Blockchain') + ':'), 2, 0)
        grid.addWidget(self.height_label, 2, 1)
        grid.addWidget(HelpButton(msg), 2, 4)

        self.split_label = QLabel('')
        self.split_label.setTextInteractionFlags(
            self.split_label.textInteractionFlags() | Qt.TextSelectableByMouse)
        grid.addWidget(self.split_label, 3, 0, 1, 3)

        self.nodes_list_widget = NodesListWidget(self)
        grid.addWidget(self.nodes_list_widget, 5, 0, 1, 5)

        vbox = QVBoxLayout()
        vbox.addWidget(tabs)
        self.layout_ = vbox

        self.fill_in_proxy_settings()
        self.update()
    def __init__(self, window):
        QWidget.__init__(self)
        self.window = window
        self.timer = QtCore.QTimer()
        self.update_inputs_timer = QtCore.QTimer()
        self.waiting_timeout = 180
        self.timer.timeout.connect(self.tick)
        self.update_inputs_timer.timeout.connect(self.update_inputs)
        self.update_inputs_timer.start(15000)
        self.coinshuffle_fee_constant = 1000
        # This is for debug
        # self.coinshuffle_fee_constant = 1000

        # self.coinshuffle_amounts = [1e7, 1e6]
        # Use this in test mode
        self.coinshuffle_amounts = [1e5, 1e6, 1e7]
        self.shuffle_grid = QGridLayout()
        self.shuffle_grid.setSpacing(8)
        self.shuffle_grid.setColumnStretch(3, 1)

        self.coinshuffle_servers = ServersList()
        self.coinshuffle_inputs = InputAdressWidget(
            decimal_point=self.window.get_decimal_point)
        self.coinshuffle_changes = ChangeAdressWidget()
        self.coinshuffle_fresh_changes = QCheckBox(
            _('Show only fresh change addresses'))
        self.coinshuffle_outputs = OutputAdressWidget()
        self.coinshuffle_amount_radio = AmountSelect(
            self.coinshuffle_amounts,
            decimal_point=self.window.get_decimal_point)
        self.coinshuffle_fee = QLabel(
            _(
                self.window.format_amount_and_units(
                    self.coinshuffle_fee_constant)))
        self.coinshuffle_text_output = ConsoleOutput()
        self.coinshuffle_timer_output = QLabel()

        self.coinshuffle_inputs.currentIndexChanged.connect(
            self.check_sufficient_ammount)
        self.coinshuffle_amount_radio.button_group.buttonClicked.connect(
            self.check_sufficient_ammount)
        self.coinshuffle_fresh_changes.stateChanged.connect(
            lambda: self.coinshuffle_changes.update(
                self.window.wallet,
                fresh_only=self.coinshuffle_fresh_changes.isChecked()))

        self.coinshuffle_start_button = EnterButton(
            _("Shuffle"), lambda: self.start_coinshuffle_protocol())
        self.coinshuffle_cancel_button = EnterButton(
            _("Cancel"), lambda: self.cancel_coinshuffle_protocol())
        self.coinshuffle_start_button.setEnabled(False)
        self.coinshuffle_cancel_button.setEnabled(False)

        self.shuffle_grid.addWidget(QLabel(_('Shuffle server')), 1, 0)
        self.shuffle_grid.addWidget(QLabel(_('Shuffle input address')), 2, 0)
        self.shuffle_grid.addWidget(QLabel(_('Shuffle change address')), 3, 0)
        self.shuffle_grid.addWidget(QLabel(_('Shuffle output address')), 5, 0)
        self.shuffle_grid.addWidget(QLabel(_('Amount')), 6, 0)
        self.shuffle_grid.addWidget(QLabel(_('Fee')), 7, 0)
        self.shuffle_grid.addWidget(self.coinshuffle_servers, 1, 1, 1, -1)
        self.shuffle_grid.addWidget(self.coinshuffle_fresh_changes, 4, 1)
        self.shuffle_grid.addWidget(self.coinshuffle_inputs, 2, 1, 1, -1)
        self.shuffle_grid.addWidget(self.coinshuffle_changes, 3, 1, 1, -1)
        self.shuffle_grid.addWidget(self.coinshuffle_outputs, 5, 1, 1, -1)
        self.shuffle_grid.addWidget(self.coinshuffle_amount_radio, 6, 1)
        self.shuffle_grid.addWidget(self.coinshuffle_fee, 7, 1)
        self.shuffle_grid.addWidget(self.coinshuffle_start_button, 8, 0)
        self.shuffle_grid.addWidget(self.coinshuffle_cancel_button, 8, 1)
        self.shuffle_grid.addWidget(self.coinshuffle_timer_output, 8, 2)
        self.shuffle_grid.addWidget(self.coinshuffle_text_output, 9, 0, 1, -1)

        vbox0 = QVBoxLayout()
        vbox0.addLayout(self.shuffle_grid)
        hbox = QHBoxLayout()
        hbox.addLayout(vbox0)
        vbox = QVBoxLayout(self)
        vbox.addLayout(hbox)
        vbox.addStretch(1)
from electroncash.i18n import _

fullname = _('Audio MODEM')
description = _('Provides support for air-gapped transaction signing.')
requires = [('amodem', 'http://github.com/romanz/amodem/')]
available_for = ['qt']
 def description(self):
     return _("Configure CashShuffle Protocol")
예제 #13
0
    def __init__(self, main_window, pmw):
        # top level window
        QDialog.__init__(self, parent=None)
        self.pmw = pmw
        self.key = pmw.key
        self.address = self.key.address
        pubkey = self.key.pubkey.hex()

        self.wallet = pmw.wallet
        self.network = pmw.wallet.network

        self.main_window = main_window
        self.config = main_window.config
        self.app = main_window.app

        self.setWindowTitle(_("OpenSwap Private Messages"))

        self.setMinimumWidth(700)
        vbox = QVBoxLayout()
        self.setLayout(vbox)

        vbox.addWidget(
            QLabel(_("Address") + ': ' + self.address.to_ui_string()))

        vbox.addWidget(QLabel(_("Public key") + ':'))
        pubkey_e = ButtonsLineEdit(pubkey)
        pubkey_e.setReadOnly(True)
        pubkey_e.addCopyButton(self.app)
        vbox.addWidget(pubkey_e)

        vbox.addWidget(QLabel(_("History")))
        self.hw = MyHistoryList(self)
        vbox.addWidget(self.hw)

        hbox = QHBoxLayout()

        b = QPushButton(_("Write"))
        b.clicked.connect(lambda: self.write_message())
        hbox.addWidget(b)

        b = QPushButton(_("Offer"))
        b.clicked.connect(lambda: self.make_offer())
        hbox.addWidget(b)

        b = QPushButton(_("View Public Offers"))
        b.clicked.connect(
            lambda: prompt_dialog(self.main_window, 0, 1, pmw=self.pmw))
        hbox.addWidget(b)

        hbox.addStretch(1)

        hbox.addWidget(CloseButton(self))

        vbox.addLayout(hbox)

        self.show()

        self.gotDecryptSig.connect(self.hw.got_decrypted)

        def on_success(result):
            pmw.callbacks_decrypted.append(self.gotDecryptSig.emit)
            self.hw.update()

        def on_error(einfo):
            import traceback
            traceback.print_exception(*einfo)

        d = WaitingDialog(self, _('Opening...'), pmw.start, on_success,
                          on_error)
예제 #14
0
    def create_menu(self, position):
        self.selectedIndexes()
        item = self.currentItem()
        if not item:
            return

        tx_hash, i = item.data(0, Qt.UserRole)
        if not tx_hash:
            return
        key = self.parent.key
        mypubkey = key.pubkey

        from_pubkey = item.data(2, Qt.UserRole)
        to_pubkey = item.data(3, Qt.UserRole)
        from_me = (from_pubkey == mypubkey)
        to_me = (to_pubkey == mypubkey)

        if from_me:
            other_pubkey = to_pubkey
        else:
            other_pubkey = from_pubkey
        packet = item.data(5, Qt.UserRole)

        column = self.currentColumn()
        if column == 0:
            column_title = "ID"
            column_data = tx_hash
        elif column == 2:
            column_title = _("sender pubkey")
            column_data = from_pubkey.hex()
        elif column == 3:
            column_title = _("recipient pubkey")
            if to_pubkey:
                column_data = to_pubkey.hex()
            else:
                column_data = ""
        else:
            column_title = self.headerItem().text(column)
            column_data = item.text(column)

        menu = QMenu()

        if isinstance(packet, openswap.PacketOffer):
            if from_me:
                menu.addAction(
                    _("View/Re-offer"),
                    lambda: self.parent.view_offer_as_sender(
                        to_pubkey, packet))
            else:
                menu.addAction(
                    _("View/Counter-offer/Accept"),
                    lambda: self.parent.view_offer_as_recipient(
                        from_pubkey, packet))

        if isinstance(packet, openswap.PacketAccept):
            if from_me:
                offerpacket = self.incoming_offers.get(
                    (to_pubkey, packet.offer_info))
            else:
                offerpacket = None
            act = menu.addAction(
                _("Atomic Swap"), lambda: self.parent.start_swap(
                    from_me, other_pubkey, offerpacket, packet))
            if from_me and not offerpacket:
                # If we have accepted other party's offer but we don't have their
                # offer packet, then we can't do a swap as the keys are not
                # available!
                act.setEnabled(False)

        if to_me:
            menu.addAction(
                _("Reply raw message"),
                lambda: self.parent.write_message(from_pubkey.hex()))
        elif to_pubkey:
            menu.addAction(_("Write another raw message"),
                           lambda: self.parent.write_message(to_pubkey.hex()))

        menu.addAction(
            _("Copy {}").format(column_title), lambda: self.parent.main_window.
            app.clipboard().setText(column_data))

        def showtx():
            tx = self.wallet.transactions.get(tx_hash)
            self.parent.main_window.show_transaction(tx)

        menu.addAction(_("View Tx"), showtx)

        menu.exec_(self.viewport().mapToGlobal(position))
예제 #15
0
 def on_uninstall_plugin(self):
     package_name = self.pluginsList.get_selected_key()
     if self.question(_("Are you sure you want to uninstall the selected plugin?")):
         plugin_manager = self.main_window.gui_object.plugins
         plugin_manager.uninstall_external_plugin(package_name)
         self.refresh_ui()
예제 #16
0
    def update(self):
        host, port, protocol, proxy_config, auto_connect = self.network.get_parameters(
        )
        preferred_only = self.network.is_whitelist_only()
        if not self.server_host.hasFocus() and not self.server_port.hasFocus():
            self.server_host.setText(host)
            self.server_port.setText(port)
        self.ssl_cb.setChecked(protocol == 's')
        ssl_disable = self.ssl_cb.isChecked() and not self.tor_cb.isChecked(
        ) and not host.lower().endswith('.onion')
        for w in [self.ssl_cb]:  #, self.ssl_help]:
            w.setDisabled(ssl_disable)
        self.autoconnect_cb.setChecked(auto_connect)
        self.preferred_only_cb.setChecked(preferred_only)

        host = self.network.interface.host if self.network.interface else _(
            'None')
        self.server_label.setText(host)

        self.set_protocol(protocol)
        self.servers = self.network.get_servers()

        def protocol_suffix():
            if protocol == 't':
                return '  (non-SSL)'
            elif protocol == 's':
                return '  [SSL]'
            return ''

        server_list_txt = (_('Server peers') if self.network.is_connected()
                           else _('Servers')) + " ({})".format(
                               len(self.servers))
        server_list_txt += protocol_suffix()
        self.server_list_label.setText(server_list_txt)
        if self.network.blacklisted_servers:
            bl_srv_ct_str = ' ({}) <a href="ViewBanList">{}</a>'.format(
                len(self.network.blacklisted_servers), _("View ban list..."))
        else:
            bl_srv_ct_str = " (0)<i> </i>"  # ensure rich text
        servers_whitelisted = set(get_eligible_servers(
            self.servers, protocol)).intersection(
                self.network.whitelisted_servers
            ) - self.network.blacklisted_servers
        self.legend_label.setText(ServerFlag.Symbol[ServerFlag.Preferred] +
                                  "=" + _("Preferred") +
                                  " ({})".format(len(servers_whitelisted)) +
                                  "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" +
                                  ServerFlag.Symbol[ServerFlag.Banned] + "=" +
                                  _("Banned") + bl_srv_ct_str)
        self.servers_list.update(self.network, self.servers, self.protocol,
                                 self.tor_cb.isChecked())
        self.enable_set_server()

        height_str = "%d " % (self.network.get_local_height()) + _('blocks')
        self.height_label.setText(height_str)
        n = len(self.network.get_interfaces())
        status = _("Connected to %d nodes.") % n if n else _("Not connected")
        if n: status += protocol_suffix()
        self.status_label.setText(status)
        chains = self.network.get_blockchains()
        if len(chains) > 1:
            chain = self.network.blockchain()
            checkpoint = chain.get_base_height()
            name = chain.get_name()
            msg = _('Chain split detected at block %d') % checkpoint + '\n'
            msg += (_('You are following branch') if auto_connect else
                    _('Your server is on branch')) + ' ' + name
            msg += ' (%d %s)' % (chain.get_branch_size(), _('blocks'))
        else:
            msg = ''
        self.split_label.setText(msg)
        self.nodes_list_widget.update(self.network)
예제 #17
0
 def show_installed_plugin_about_dialog(self, package_name):
     plugin_manager = self.main_window.gui_object.plugins
     metadata = plugin_manager.external_plugin_metadata.get(package_name, None)
     if metadata is None:
         return
     self.pluginAboutDialog = d = ExternalPluginsPreviewDialog(self, self.main_window, _("Plugin Details"), plugin_metadata=metadata)
     d.exec_()
예제 #18
0
    def __init__(self, main_window, exctype, value, tb):
        self.exc_args = (exctype, value, tb)
        self.main_window = main_window
        QWidget.__init__(self)
        self.setWindowTitle('Electron Cash - ' + _('An Error Occurred'))
        self.setMinimumSize(600, 300)

        main_box = QVBoxLayout()

        heading = QLabel('<h2>' + _('Sorry!') + '</h2>')
        main_box.addWidget(heading)
        main_box.addWidget(
            QLabel(_('Something went wrong running Electron Cash.')))

        main_box.addWidget(
            QLabel(
                _('To help us diagnose and fix the problem, you can send us a bug report that contains useful debug '
                  'information:')))

        collapse_info = QPushButton(_("Show report contents"))
        collapse_info.clicked.connect(lambda: QMessageBox.about(
            self, "Report contents", self.get_report_string()))
        main_box.addWidget(collapse_info)

        label = QLabel(
            _("Please briefly describe what led to the error (optional):") +
            "<br/>" + "<i>" +
            _("Feel free to add your email address if you are willing to provide further detail, but note that it will appear in the relevant github issue."
              ) + "</i>")
        label.setTextFormat(QtCore.Qt.RichText)
        main_box.addWidget(label)

        self.description_textfield = QTextEdit()
        self.description_textfield.setFixedHeight(50)
        main_box.addWidget(self.description_textfield)

        main_box.addWidget(QLabel(_("Do you want to send this report?")))

        buttons = QHBoxLayout()

        report_button = QPushButton(_('Send Bug Report'))
        report_button.clicked.connect(self.send_report)
        report_button.setIcon(QIcon(":icons/tab_send.png"))
        buttons.addWidget(report_button)

        never_button = QPushButton(_('Never'))
        never_button.clicked.connect(self.show_never)
        buttons.addWidget(never_button)

        close_button = QPushButton(_('Not Now'))
        close_button.clicked.connect(self.close)
        buttons.addWidget(close_button)

        main_box.addLayout(buttons)

        self.setLayout(main_box)
        self.show()
예제 #19
0
    def create_menu(self, position):
        menu = QMenu()
        selected = self.selectedItems()
        i2c = self._i2c
        ca_unverified = self._get_ca_unverified(include_temp=False)
        if selected:
            names = [item.text(1) for item in selected]
            keys = [i2c(item) for item in selected]
            payable_keys = [k for k in keys if k.type != 'cashacct_T']
            deletable_keys = [k for k in keys if k.type in contact_types]
            needs_verif_keys = [k for k in keys if k in ca_unverified]
            column = self.currentColumn()
            column_title = self.headerItem().text(column)
            column_data = '\n'.join([item.text(column) for item in selected])
            item = self.currentItem()
            typ = i2c(item).type if item else 'unknown'
            ca_info = None
            if item and typ in ('cashacct', 'cashacct_W'):
                ca_info = self.wallet.cashacct.get_verified(i2c(item).name)
                if column == 1 and len(selected) == 1:
                    # hack .. for Cash Accounts just say "Copy Cash Account"
                    column_title = _('Cash Account')
                    if ca_info:
                        column_data = self.wallet.cashacct.fmt_info(ca_info,
                                                                    emoji=True)
            if len(selected) > 1:
                column_title += f" ({len(selected)})"
            menu.addAction(
                _("Copy {}").format(column_title),
                lambda: self.parent.app.clipboard().setText(column_data))
            if item and column in self.editable_columns and self.on_permit_edit(
                    item, column):
                key = item.data(0, self.DataRoles.Contact)
                # this key & find_item business is so we don't hold a reference
                # to the ephemeral item, which may be deleted while the
                # context menu is up.  Accessing the item after on_update runs
                # means the item is deleted and you get a C++ object deleted
                # runtime error.
                menu.addAction(
                    _("Edit {}").format(column_title),
                    lambda: self._on_edit_item(key, column))
            a = menu.addAction(
                _("Pay to"), lambda: self.parent.payto_contacts(payable_keys))
            if needs_verif_keys or not payable_keys:
                a.setDisabled(True)
            a = menu.addAction(
                _("Delete"),
                lambda: self.parent.delete_contacts(deletable_keys))
            if not deletable_keys:
                a.setDisabled(True)
            URLs = [
                web.BE_URL(self.config, 'addr',
                           Address.from_string(key.address)) for key in keys
                if Address.is_valid(key.address)
            ]
            a = menu.addAction(_("View on block explorer"),
                               lambda: [URL and webopen(URL) for URL in URLs])
            if not any(URLs):
                a.setDisabled(True)
            if ca_info:
                menu.addAction(
                    _("View registration tx..."),
                    lambda: self.parent.do_process_from_txid(
                        txid=ca_info.txid,
                        tx_desc=self.wallet.get_label(ca_info.txid)))
                if typ in ('cashacct_W', 'cashacct'):
                    _contact_d = i2c(item)
                    menu.addAction(
                        _("Details..."),
                        lambda: cashacctqt.cash_account_detail_dialog(
                            self.parent, _contact_d.name))
            menu.addSeparator()

        menu.addAction(self.icon_cashacct,
                       _("Add Contact") + " - " + _("Cash Account"),
                       self.new_cash_account_contact_dialog)
        menu.addAction(self.icon_contacts,
                       _("Add Contact") + " - " + _("Address"),
                       self.parent.new_contact_dialog)
        menu.addSeparator()
        menu.addAction(self.icon_cashacct, _("Register Cash Account..."),
                       self.parent.register_new_cash_account)
        menu.addSeparator()
        menu.addAction(
            QIcon(":icons/import.svg" if not ColorScheme.dark_scheme else
                  ":icons/import_dark_theme.svg"), _("Import file"),
            self.import_contacts)
        if not self.parent.contacts.empty:
            menu.addAction(
                QIcon(":icons/save.svg" if not ColorScheme.dark_scheme else
                      ":icons/save_dark_theme.svg"), _("Export file"),
                self.export_contacts)

        menu.addSeparator()
        a = menu.addAction(_("Show My Cash Accounts"),
                           self.toggle_show_my_cashaccts)
        a.setCheckable(True)
        a.setChecked(self.show_my_cashaccts)

        if ca_unverified:

            def kick_off_verify():
                bnums = set()
                for contact in ca_unverified:
                    tup = self.wallet.cashacct.parse_string(contact.name)
                    if not tup:
                        continue
                    bnums.add(tup[1])  # number
                ret = cashacctqt.verify_multiple_blocks(
                    bnums, self.parent, self.wallet)
                if ret is None:
                    # user cancel
                    return
                verified = ca_unverified - self._get_ca_unverified()
                if not verified:
                    self.parent.show_error(
                        _("Cash Account verification failure"))

            menu.addSeparator()
            num = len(ca_unverified)
            a = menu.addAction(
                self.icon_unverif,
                ngettext("Verify {count} Cash Account",
                         "Verify {count} Cash Accounts",
                         num).format(count=num), kick_off_verify)
            if not self.wallet.network:
                a.setDisabled(True)

        run_hook('create_contact_menu', menu, selected)
        menu.exec_(self.viewport().mapToGlobal(position))
예제 #20
0
 def decrypt_message(self, sequence, message, password):
     raise RuntimeError(
         _('Encryption and decryption are not implemented by {}').format(
             self.device))
예제 #21
0
from electroncash.constants import PROJECT_NAME
from electroncash import keystore
from electroncash.wallet import Standard_Wallet

from .seed_dialog import SeedLayout, KeysLayout
from .network_dialog import NetworkChoiceLayout
from .util import *
from .password_dialog import PasswordLayout, PW_NEW
from .bip38_importer import Bip38Importer


class GoBack(Exception):
    pass


MSG_GENERATING_WAIT = _(
    f"{PROJECT_NAME} is generating your addresses, please wait...")
MSG_ENTER_ANYTHING = _("Please enter a seed phrase, a master key, a list of "
                       "Bitcoin addresses, or a list of private keys")
MSG_ENTER_SEED_OR_MPK = _(
    "Please enter a seed phrase or a master key (xpub or xprv):")
MSG_COSIGNER = _("Please enter the master public key of cosigner #{}:")
MSG_ENTER_PASSWORD = _("Choose a password to encrypt your wallet keys.") + '\n'\
                     + _("Leave this field empty if you want to disable encryption.")
MSG_RESTORE_PASSPHRASE = \
    _("Please enter your seed derivation passphrase. "
      "Note: this is NOT your encryption password. "
      "Leave this field empty if you did not use one or are unsure.")


class CosignWidget(QWidget):
    size = 120
예제 #22
0
 def decrypt_message(self, pubkey, message, password):
     raise RuntimeError(
         _('Encryption and decryption are currently not supported for %s') %
         self.device)
예제 #23
0
 def on_m(m):
     m_label.setText(_('Require %d signatures') % m)
     cw.set_m(m)
예제 #24
0
    def sign_transaction(self, tx, password):
        if tx.is_complete():
            return
        client = self.get_client()
        self.signing = True
        inputs = []
        inputsPaths = []
        pubKeys = []
        chipInputs = []
        redeemScripts = []
        signatures = []
        preparedTrustedInputs = []
        changePath = ""
        changeAmount = None
        output = None
        outputAmount = None
        p2shTransaction = False
        pin = ""
        self.get_client(
        )  # prompt for the PIN before displaying the dialog if necessary

        # Fetch inputs of the transaction to sign
        derivations = self.get_tx_derivations(tx)
        for txin in tx.inputs():
            if txin['type'] == 'coinbase':
                self.give_error(
                    "Coinbase not supported")  # should never happen

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

            pubkeys, x_pubkeys = tx.get_sorted_pubkeys(txin)
            for i, x_pubkey in enumerate(x_pubkeys):
                if x_pubkey in derivations:
                    signingPos = i
                    s = derivations.get(x_pubkey)
                    hwAddress = "%s/%d/%d" % (self.get_derivation()[2:], s[0],
                                              s[1])
                    break
            else:
                self.give_error("No matching x_key for sign_transaction"
                                )  # should never happen

            redeemScript = Transaction.get_preimage_script(txin)
            inputs.append([
                txin['prev_tx'].raw, txin['prevout_n'], redeemScript,
                txin['prevout_hash'], signingPos,
                txin.get('sequence', 0xffffffff - 1)
            ])
            inputsPaths.append(hwAddress)
            pubKeys.append(pubkeys)

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

        txOutput = var_int(len(tx.outputs()))
        for txout in tx.outputs():
            output_type, addr, amount = txout
            txOutput += int_to_hex(amount, 8)
            script = tx.pay_script(addr)
            txOutput += var_int(len(script) // 2)
            txOutput += script
        txOutput = bfh(txOutput)

        # Recognize outputs - only one output and one change is authorized
        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) and (len(tx.outputs()) != 1):
                    index, xpubs, m = info
                    changePath = self.get_derivation()[2:] + "/%d/%d" % index
                    changeAmount = amount
                else:
                    output = address
                    outputAmount = amount

        self.handler.show_message(
            _("Confirm Transaction on your Ledger device..."))
        try:
            # Get trusted inputs from the original transactions
            for utxo in inputs:
                sequence = int_to_hex(utxo[5], 4)
                txtmp = bitcoinTransaction(bfh(utxo[0]))
                tmp = bfh(utxo[3])[::-1]
                tmp += bfh(int_to_hex(utxo[1], 4))
                tmp += txtmp.outputs[utxo[1]].amount
                chipInputs.append({
                    'value': tmp,
                    'witness': True,
                    'sequence': sequence
                })
                redeemScripts.append(bfh(utxo[2]))

            # Sign all inputs
            inputIndex = 0
            rawTx = tx.serialize()
            self.get_client().enableAlternate2fa(False)
            self.get_client().startUntrustedTransaction(
                True, inputIndex, chipInputs, redeemScripts[inputIndex])
            outputData = self.get_client().finalizeInputFull(txOutput)
            outputData['outputData'] = txOutput
            transactionOutput = outputData['outputData']
            if outputData['confirmationNeeded']:
                outputData['address'] = output
                self.handler.finished()
                pin = self.handler.get_auth(
                    outputData)  # does the authenticate dialog and returns pin
                if not pin:
                    raise UserWarning()
                if pin != 'paired':
                    self.handler.show_message(
                        _("Confirmed. Signing Transaction..."))
            while inputIndex < len(inputs):
                singleInput = [chipInputs[inputIndex]]
                self.get_client().startUntrustedTransaction(
                    False, 0, singleInput, redeemScripts[inputIndex])
                inputSignature = self.get_client().untrustedHashSign(
                    inputsPaths[inputIndex],
                    pin,
                    lockTime=tx.locktime,
                    sighashType=tx.nHashType())
                inputSignature[0] = 0x30  # force for 1.4.9+
                signatures.append(inputSignature)
                inputIndex = inputIndex + 1
        except UserWarning:
            self.handler.show_error(_('Cancelled by user'))
            return
        except BaseException as e:
            traceback.print_exc(file=sys.stdout)
            self.give_error(e, True)
        finally:
            self.handler.finished()

        for i, txin in enumerate(tx.inputs()):
            signingPos = inputs[i][4]
            txin['signatures'][signingPos] = bh2u(signatures[i])
        tx.raw = tx.serialize()
        self.signing = False
예제 #25
0
 def notify_offline(self):
     for i, p in enumerate(self.DERIVATION_PATHS):
         self.update_table_cb(i, _('Offline'))
예제 #26
0
def show_contact_options_actionsheet(contact: ContactsEntry,
                                     vc: ObjCInstance,
                                     view: ObjCInstance,
                                     navBackOnDelete=False,
                                     onEdit=None) -> None:
    #print ("On Options But")
    try:
        parent = gui.ElectrumGui.gui

        def on_block_explorer() -> None:
            parent.view_on_block_explorer(contact.address, 'addr')

        def on_pay_to() -> None:
            pay_to([contact.address_str])

        def on_cpy() -> None:
            parent.copy_to_clipboard(contact.address_str, 'Address')
            print("copied to clipboard =", contact.address_str)

        def on_edit() -> None:
            show_new_edit_contact(contact, vc, onEdit=onEdit)

        def on_delete() -> None:
            def doDelete() -> None:
                if delete_contact(contact):
                    _Updated()
                if navBackOnDelete and vc.navigationController:
                    vc.navigationController.popViewControllerAnimated_(True)
                #utils.show_notification(message = _("Contact deleted."))

            parent.question(
                title=_("Confirm Delete"),
                message=_("Are you sure you wish to delete this contact?"),
                onOk=doDelete,
                vc=vc,
                destructive=True,
                okButTitle=_('Delete'))

        actions = [
            [_('Cancel')],
            [_("Copy Address"), on_cpy],
            [_("Edit Contact"), on_edit],
            [_("Pay to"), on_pay_to],
            [_("View on block explorer"), on_block_explorer],
            [_("Delete"), on_delete],
        ]

        if parent.wallet.is_watching_only():
            actions.pop(3)

        if isinstance(vc, ContactDetailVC):
            actions.insert(2, [_('Share/Save QR...'), lambda: vc.onQRImgTap()])

        utils.show_alert(
            vc=vc,
            title=contact.name,  #_("Options"),
            message=contact.address_str,
            actions=actions,
            cancel=_('Cancel'),
            destructive=_('Delete'),
            style=UIAlertControllerStyleActionSheet,
            ipadAnchor=view.convertRect_toView_(view.bounds, vc.view)
            if isinstance(view, UIView) else view)
        #print ("address =", entry.address_str)
    except:
        utils.NSLog(
            "*** WARNING: Exception during contacts.py 'show_contact_options_actionsheet': %s",
            str(sys.exc_info()[1]))
예제 #27
0
 def set_scan_progress(self, n):
     self.label.setText(
         _('Scanned {}/{}').format(
             n, len(DerivationPathScanner.DERIVATION_PATHS)))
예제 #28
0
import hashlib
import urllib.parse
import sys

from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *

from electroncash.i18n import _
from electroncash.plugins import ExternalPluginCodes, run_hook
from .util import MyTreeWidget, MessageBoxMixin, WindowModalDialog, Buttons, CloseButton


INSTALL_ERROR_MESSAGES = {
    ExternalPluginCodes.MISSING_MANIFEST: _("The plugin archive you selected is missing a manifest. It was therefore not possible to install it."),
    ExternalPluginCodes.NAME_ALREADY_IN_USE: _("There is already a plugin installed using the internal package name of the plugin you selected. It was therefore not possible to install it."),
    ExternalPluginCodes.UNABLE_TO_COPY_FILE: _("It was not possible to copy the plugin archive into Electron Cash's plugin storage location. It was therefore not possible to install it."),
    ExternalPluginCodes.INSTALLED_BUT_FAILED_LOAD: _("The plugin is installed, but in the process of enabling and loading it, an error occurred. Restart Electron Cash and try again, or uninstall it and report it to it's developers."),
    ExternalPluginCodes.INCOMPATIBLE_VERSION: _("The plugin is targeted at a later version of ViLight."),
    ExternalPluginCodes.INCOMPATIBLE_ZIP_FORMAT: _("The plugin archive is not recognized as a valid Zip file."),
    ExternalPluginCodes.INVALID_MANIFEST_JSON: _("The plugin manifest is not recognized as valid JSON."),
    ExternalPluginCodes.INVALID_MAMIFEST_DISPLAY_NAME: _("The plugin manifest lacks a valid display name."),
    ExternalPluginCodes.INVALID_MAMIFEST_DESCRIPTION: _("The plugin manifest lacks a valid description."),
    ExternalPluginCodes.INVALID_MAMIFEST_VERSION: _("The plugin manifest lacks a valid version."),
    ExternalPluginCodes.INVALID_MAMIFEST_MINIMUM_EC_VERSION: _("The plugin manifest lacks a valid minimum Electron Cash version."),
    ExternalPluginCodes.INVALID_MAMIFEST_PACKAGE_NAME: _("The plugin manifest lacks a valid package name."),
}


class ExternalPluginsPreviewDialog(WindowModalDialog):
예제 #29
0
파일: ledger.py 프로젝트: proteanx/DeLight
    def perform_hw1_preflight(self):
        try:
            firmwareInfo = self.dongleObject.getFirmwareVersion()
            firmwareVersion = versiontuple(firmwareInfo['version'])
            self.bitcoinCashSupported = firmwareVersion >= BITCOIN_CASH_SUPPORT or \
                self.is_hw1() and firmwareVersion >= BITCOIN_CASH_SUPPORT_HW1
            self.cashaddrFWSupported = firmwareVersion >= CASHADDR_SUPPORT
            self.multiOutputSupported = firmwareVersion >= MULTI_OUTPUT_SUPPORT

            if not checkFirmware(
                    firmwareInfo) or not self.supports_bitcoin_cash():
                self.dongleObject.dongle.close()
                raise Exception(
                    _("{} firmware version too old. Please update at https://www.ledgerwallet.com"
                      ).format(self.device))
            try:
                self.dongleObject.getOperationMode()
            except BTChipException as e:
                if (e.sw == 0x6985):
                    self.dongleObject.dongle.close()
                    self.handler.get_setup()
                    # Acquire the new client on the next run
                else:
                    raise e
            if self.has_detached_pin_support(
                    self.dongleObject) and not self.is_pin_validated(
                        self.dongleObject) and (self.handler is not None):
                remaining_attempts = self.dongleObject.getVerifyPinRemainingAttempts(
                )
                if remaining_attempts != 1:
                    msg = _(
                        'Enter your {} PIN - remaining attempts: {}').format(
                            self.device, remaining_attempts)
                else:
                    msg = _(
                        'Enter your {} PIN - WARNING: LAST ATTEMPT. If the PIN is not correct, the {} will be wiped.'
                    ).format(self.device, self.device)
                confirmed, p, pin = self.password_dialog(msg)
                if not confirmed:
                    raise Exception(
                        _('Aborted by user - please unplug the {} and plug it again before retrying'
                          ).format(self.device))
                pin = pin.encode()
                self.dongleObject.verifyPin(pin)

            gwpkArgSpecs = inspect.getfullargspec(
                self.dongleObject.getWalletPublicKey)
            self.cashaddrSWSupported = 'cashAddr' in gwpkArgSpecs.args
        except BTChipException as e:
            if (e.sw == 0x6faa):
                raise Exception(
                    _('{} is temporarily locked - please unplug it and replug it again'
                      ).format(self.device))
            if ((e.sw & 0xFFF0) == 0x63c0):
                raise Exception(
                    _('Invalid PIN - please unplug the {} and plug it again before retrying'
                      ).format(self.device))
            if e.sw == 0x6f00 and e.message == 'Invalid channel':
                # based on docs 0x6f00 might be a more general error, hence we also compare message to be sure
                raise Exception(
                    _('Invalid channel.') + '\n' +
                    _('Please make sure that \'Browser support\' is disabled on your {}.'
                      ).format(self.device))
            raise e
예제 #30
0
 def _ca_set_item_tooltip(self, item, ca_info):
     minimal_chash = getattr(ca_info, 'minimal_chash', None)
     info_str = self.wallet.cashacct.fmt_info(ca_info, minimal_chash)
     item.setToolTip(
         0, "<i>" + _("Cash Account:") + "</i><p>&nbsp;&nbsp;<b>" +
         f"{info_str}</b>")