예제 #1
0
    def _copy_electron_cash_wallets(self):
        """
        Work out whether we should show UI to offer to copy the user's
        Electron Cash wallets to their ElectrumSV wallet directory, and
        if so, show it and give them the chance.
        """
        # If the user has ElectrumSV wallets already, we do not offer to copy the one's
        # Electron Cash has.
        esv_wallets_dir = os.path.join(app_state.config.electrum_path(),
                                       "wallets")
        if len(self._list_user_wallets(esv_wallets_dir)) > 0:
            return

        ec_wallets_dir = get_electron_cash_user_dir(esv_wallets_dir)
        ec_wallet_count = len(self._list_user_wallets(ec_wallets_dir))
        # If the user does not have Electron Cash wallets to copy, there's no point in offering.
        if ec_wallet_count == 0:
            return

        vbox, file_list = self._create_copy_electron_cash_wallets_layout(
            ec_wallets_dir)
        self._set_standard_layout(vbox,
                                  title=_('Import Electron Cash wallets'))

        v = self.loop.exec_()
        # Cancel, exit application.
        if v == -1:
            raise UserCancelled()
        if v != 2:
            raise GoBack()

        self._do_copy_electron_cash_wallets(file_list, esv_wallets_dir,
                                            ec_wallets_dir)
예제 #2
0
    def select_storage(self, initial_path: str, is_startup=False):
        if is_startup:
            self._copy_electron_cash_wallets()

        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 = PasswordLineEdit()
        self.pw_e.setMinimumWidth(200)
        self.pw_label = QLabel(_('Password') + ':')
        self.pw_label.setAlignment(Qt.AlignTop)
        hbox2.addWidget(self.pw_label)
        hbox2.addWidget(self.pw_e)
        hbox2.addStretch()
        vbox.addLayout(hbox2)
        self._set_standard_layout(vbox,
                                  title=_('ElectrumSV wallet'),
                                  back_text=_(MSG_BUTTON_CANCEL))

        esv_wallets_dir = os.path.join(app_state.config.electrum_path(),
                                       "wallets")

        if is_startup:

            def _show_copy_electron_cash_wallets_dialog(*args):
                nonlocal esv_wallets_dir, ec_wallets_dir

                d = WindowModalDialog(self, _("Copy Electron Cash Wallets"))
                d.setMinimumWidth(400)

                vbox, file_list = self._create_copy_electron_cash_wallets_layout(
                    ec_wallets_dir)

                bbox = QDialogButtonBox(QDialogButtonBox.Ok
                                        | QDialogButtonBox.Cancel)
                bbox.rejected.connect(d.reject)
                bbox.accepted.connect(d.accept)
                vbox.addWidget(bbox)

                d.setLayout(vbox)

                result = d.exec()
                if result == QDialog.Accepted:
                    self._do_copy_electron_cash_wallets(
                        file_list, esv_wallets_dir, ec_wallets_dir)

                _update_selected_wallet()

            ec_import_text = ("<p>" + _(
                "You have previously run Electron Cash and created at " +
                "least one wallet with it. ElectrumSV should not be used to open these wallets "
                +
                "directly using the 'Choose' button, and you should instead use the 'Import' "
                + "button to help you copy them."
            ) + "</p>" + "<p>" + _(
                "There are many reasons for this, and the simplest is that if Electron Cash "
                +
                "and ElectrumSV were to operate on the same wallet at the same time, then the "
                +
                "wallet will most likely become corrupted. It's simpler in every way to just "
                +
                "copy the wallet over to ElectrumSV and use a separate wallet file for each."
            ) + "</p>")
            ec_import_icon = HelpLabel("label text", ec_import_text)
            ec_import_icon.setPixmap(
                QPixmap(icon_path("icons8-info.svg")).scaledToWidth(
                    16, Qt.SmoothTransformation))
            ec_import_label = QLabel(
                _("Existing Electron Cash wallets detected"))
            ec_import_button = QPushButton(_("Import..."))
            ec_import_button.clicked.connect(
                _show_copy_electron_cash_wallets_dialog)
            self.template_hbox.addWidget(ec_import_icon)
            self.template_hbox.addWidget(ec_import_label)
            self.template_hbox.addWidget(ec_import_button)
            self.template_hbox.addStretch(1)

            ec_wallets_dir = get_electron_cash_user_dir(esv_wallets_dir)
            if len(self._list_user_wallets(ec_wallets_dir)) == 0:
                ec_import_icon.set_help_text("<p>" + _(
                    "This feature is aimed at users who were " +
                    "already using Electron Cash and have existing wallets associated with it. "
                    +
                    "None were detected on this computer, but if you do have some stored in "
                    +
                    "places ElectrumSV does not know about you may need to copy them "
                    + "yourself."
                ) + "</p>" + "<p>" + _(
                    "You should never open your existing Electron Cash wallets directly in "
                    +
                    "ElectrumSV as this can lead to them being opened in both applications at "
                    + "the same time, and can result in corruption.") + "</p>")
                ec_import_button.setEnabled(False)
                ec_import_button.setToolTip(_("Nothing to import"))
                ec_import_label.setText(_("No Electron Cash wallets detected"))

        if WalletStorage.files_are_matched_by_path(initial_path):
            self._storage_existing = WalletStorage(initial_path,
                                                   manual_upgrades=True)

        wallet_folder = os.path.dirname(initial_path)

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

        def _on_filename(filename: str) -> None:
            pw = False
            self._storage_existing = None

            # A relative path will be relative to the folder we offered in the choose dialog.
            # An absolute path will not get joined to the dialog folder (no-op).
            path = os.path.join(wallet_folder, filename)
            if WalletStorage.files_are_matched_by_path(path):
                try:
                    self._storage_existing = WalletStorage(
                        path, manual_upgrades=True)
                except IOError:
                    self.next_button.setEnabled(False)
                    msg = _('Cannot read file')
                else:
                    self.next_button.setEnabled(True)
                    if self._storage_existing.is_encrypted():
                        msg = '\n'.join([
                            _("This file is encrypted."),
                            _('Enter your password or choose another file.'),
                        ])
                        pw = True
                    else:
                        msg = _("Press 'Next' to open this wallet.")
            else:
                msg = _("This file does not exist.")
                if os.access(wallet_folder, os.W_OK):
                    self.next_button.setEnabled(True)
                    msg += "\n" + _(
                        "Press 'Next' to create this wallet, or choose another file."
                    )
                    self._path_new = path
                else:
                    self.next_button.setEnabled(False)
                    msg += "\n" + _("You do not have write access " +
                                    "to this folder to create a new wallet.")

            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()

        def _update_selected_wallet(
                skip_pick_most_recent: bool = False) -> None:
            wallet_filename = None
            if is_startup and not skip_pick_most_recent and self._storage_existing is None:
                esv_wallet_names = self._list_user_wallets(esv_wallets_dir)
                if len(esv_wallet_names):
                    wallet_filename = esv_wallet_names[0]
            if wallet_filename is None:
                if self._storage_existing is not None:
                    wallet_filename = os.path.basename(
                        self._storage_existing.get_path())
                else:
                    wallet_filename = os.path.basename(initial_path)
            self.name_e.setText(wallet_filename)

        button.clicked.connect(_on_choose)
        self.name_e.textChanged.connect(_on_filename)

        # We do not pick the most recent when first displaying the wizard because we want to
        # treat the preselected wallet as the user's explicit choice. So a non-existent name
        # should be a possible wallet creation.
        _update_selected_wallet(skip_pick_most_recent=True)

        while True:
            if self._storage_existing is not None and not self._storage_existing.is_encrypted(
            ):
                break
            if self.loop.exec_() != 2:  # 2 = next
                return
            if self._storage_existing is None:
                break
            if self._storage_existing is not None and self._storage_existing.is_encrypted(
            ):
                password = self.pw_e.text()
                try:
                    self._storage_existing.decrypt(password)
                    self.pw_e.setText('')
                    break
                except DecryptionError:
                    QMessageBox.information(None, _('Error'),
                                            _("Incorrect password"))
                    continue
                except Exception as e:
                    logger.exception("decrypting storage")
                    QMessageBox.information(None, _('Error'), str(e))
                    return

        return True
예제 #3
0
    def _copy_electron_cash_wallets(self):
        """
        Work out whether we should show UI to offer to copy the user's
        Electron Cash wallets to their ElectrumSV wallet directory, and
        if so, show it and give them the chance.
        """
        def ignore_wallet_file(wallet_path):
            if os.path.isdir(wallet_path):
                return True
            if wallet_path.startswith("."):
                return True
            return False

        def count_user_wallets(wallets_path):
            if os.path.exists(wallets_path):
                filenames = [
                    filename for filename in os.listdir(wallets_path)
                    if not ignore_wallet_file(
                        os.path.join(wallets_path, filename))
                ]
                return len(filenames)
            return 0

        # If the user has ElectrumSV wallets already, we do not offer to copy the one's
        # Electron Cash has.
        esv_wallets_dir = os.path.join(platform.user_dir(), "wallets")
        if count_user_wallets(esv_wallets_dir) > 0:
            return
        ec_wallets_dir = get_electron_cash_user_dir(esv_wallets_dir)
        ec_wallet_count = count_user_wallets(ec_wallets_dir)
        # If the user does not have Electron Cash wallets to copy, there's no point in offering.
        if ec_wallet_count == 0:
            return

        def update_summary_label():
            selection_count = len(file_list.selectedItems())
            if selection_count == 0:
                summary_label.setText(
                    _("No wallets are selected / will be copied."))
            elif selection_count == 1:
                summary_label.setText(
                    _("1 wallet is selected / will be copied."))
            else:
                summary_label.setText(
                    _("%d wallets are selected / will be copied.") %
                    selection_count)

        wallet_filenames = sorted(os.listdir(ec_wallets_dir),
                                  key=lambda s: s.lower())

        file_list = QListWidget()
        file_list.setSelectionMode(QAbstractItemView.ExtendedSelection)
        for filename in wallet_filenames:
            if not ignore_wallet_file(os.path.join(ec_wallets_dir, filename)):
                file_list.addItem(QListWidgetItem(filename))
        file_list.itemSelectionChanged.connect(update_summary_label)

        vbox = QVBoxLayout()
        introduction_label = QLabel(
            _("Your Electron Cash wallet directory was found. If you want ElectrumSV to import "
              "any of them on your behalf, select the ones you want copied from the list below "
              "before clicking the Next button."))
        introduction_label.setWordWrap(True)
        vbox.setSpacing(20)
        vbox.addWidget(introduction_label)
        vbox.addWidget(file_list)
        summary_label = QLabel()
        update_summary_label()
        vbox.addWidget(summary_label)
        self._set_standard_layout(vbox,
                                  title=_('Import Electron Cash wallets'))

        v = self.loop.exec_()
        # Cancel, exit application.
        if v == -1:
            raise UserCancelled()
        if v != 2:
            raise GoBack()

        # If the user selected any files, then we copy them before exiting to the next page.
        for item in file_list.selectedItems():
            filename = item.text()
            source_path = os.path.join(ec_wallets_dir, filename)
            target_path = os.path.join(esv_wallets_dir, filename)
            try:
                shutil.copyfile(source_path, target_path)
            except shutil.Error:
                # For now we ignore copy errors.
                pass