2021-04-06 14:13:51 +02:00
|
|
|
import os
|
2023-02-22 14:17:57 +01:00
|
|
|
import threading
|
2021-04-06 14:13:51 +02:00
|
|
|
|
|
|
|
|
from PyQt5.QtCore import Qt, QAbstractListModel, QModelIndex
|
2022-07-27 10:23:35 +02:00
|
|
|
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject
|
2021-04-06 14:13:51 +02:00
|
|
|
|
2022-07-28 18:43:06 +02:00
|
|
|
from electrum.i18n import _
|
2021-04-06 14:13:51 +02:00
|
|
|
from electrum.logging import get_logger
|
2022-07-27 10:23:35 +02:00
|
|
|
from electrum.util import WalletFileException, standardize_path
|
|
|
|
|
from electrum.wallet import Abstract_Wallet
|
2022-09-08 12:19:38 +02:00
|
|
|
from electrum.plugin import run_hook
|
2022-08-04 21:52:22 +02:00
|
|
|
from electrum.lnchannel import ChannelState
|
2023-03-29 22:09:46 +00:00
|
|
|
from electrum.daemon import Daemon
|
2021-04-06 14:13:51 +02:00
|
|
|
|
2022-07-27 10:23:35 +02:00
|
|
|
from .auth import AuthMixin, auth_protect
|
|
|
|
|
from .qefx import QEFX
|
2021-04-06 14:13:51 +02:00
|
|
|
from .qewallet import QEWallet
|
2022-05-06 15:36:36 +02:00
|
|
|
from .qewalletdb import QEWalletDB
|
2022-10-04 19:47:29 +02:00
|
|
|
from .qewizard import QENewWalletWizard, QEServerConnectWizard
|
2021-04-06 14:13:51 +02:00
|
|
|
|
|
|
|
|
# wallet list model. supports both wallet basenames (wallet file basenames)
|
|
|
|
|
# and whole Wallet instances (loaded wallets)
|
|
|
|
|
class QEWalletListModel(QAbstractListModel):
|
|
|
|
|
_logger = get_logger(__name__)
|
|
|
|
|
|
|
|
|
|
# define listmodel rolemap
|
|
|
|
|
_ROLE_NAMES= ('name','path','active')
|
2022-04-14 11:20:00 +02:00
|
|
|
_ROLE_KEYS = range(Qt.UserRole, Qt.UserRole + len(_ROLE_NAMES))
|
2021-04-06 14:13:51 +02:00
|
|
|
_ROLE_MAP = dict(zip(_ROLE_KEYS, [bytearray(x.encode()) for x in _ROLE_NAMES]))
|
|
|
|
|
|
2022-11-11 12:00:07 +01:00
|
|
|
def __init__(self, daemon, parent=None):
|
|
|
|
|
QAbstractListModel.__init__(self, parent)
|
|
|
|
|
self.daemon = daemon
|
|
|
|
|
self.reload()
|
|
|
|
|
|
2021-04-06 14:13:51 +02:00
|
|
|
def rowCount(self, index):
|
|
|
|
|
return len(self.wallets)
|
|
|
|
|
|
|
|
|
|
def roleNames(self):
|
|
|
|
|
return self._ROLE_MAP
|
|
|
|
|
|
|
|
|
|
def data(self, index, role):
|
2022-11-11 12:00:07 +01:00
|
|
|
(wallet_name, wallet_path) = self.wallets[index.row()]
|
2022-04-14 11:20:00 +02:00
|
|
|
role_index = role - Qt.UserRole
|
2021-04-06 14:13:51 +02:00
|
|
|
role_name = self._ROLE_NAMES[role_index]
|
|
|
|
|
if role_name == 'name':
|
|
|
|
|
return wallet_name
|
|
|
|
|
if role_name == 'path':
|
2021-04-07 16:48:40 +02:00
|
|
|
return wallet_path
|
2021-04-06 14:13:51 +02:00
|
|
|
if role_name == 'active':
|
2022-11-11 12:00:07 +01:00
|
|
|
return self.daemon.get_wallet(wallet_path) is not None
|
2021-04-06 14:13:51 +02:00
|
|
|
|
2022-11-11 12:00:07 +01:00
|
|
|
@pyqtSlot()
|
|
|
|
|
def reload(self):
|
|
|
|
|
self._logger.debug('enumerating available wallets')
|
2022-11-11 12:28:00 +01:00
|
|
|
self.beginResetModel()
|
|
|
|
|
self.wallets = []
|
|
|
|
|
self.endResetModel()
|
2022-11-11 12:00:07 +01:00
|
|
|
|
|
|
|
|
available = []
|
|
|
|
|
wallet_folder = os.path.dirname(self.daemon.config.get_wallet_path())
|
|
|
|
|
with os.scandir(wallet_folder) as it:
|
|
|
|
|
for i in it:
|
|
|
|
|
if i.is_file() and not i.name.startswith('.'):
|
|
|
|
|
available.append(i.path)
|
|
|
|
|
for path in sorted(available):
|
|
|
|
|
wallet = self.daemon.get_wallet(path)
|
|
|
|
|
self.add_wallet(wallet_path = path)
|
|
|
|
|
|
|
|
|
|
def add_wallet(self, wallet_path):
|
2022-10-31 16:13:22 +00:00
|
|
|
self.beginInsertRows(QModelIndex(), len(self.wallets), len(self.wallets))
|
2022-11-11 12:00:07 +01:00
|
|
|
wallet_name = os.path.basename(wallet_path)
|
2022-07-28 18:43:06 +02:00
|
|
|
wallet_path = standardize_path(wallet_path)
|
2022-11-11 12:00:07 +01:00
|
|
|
item = (wallet_name, wallet_path)
|
2022-10-31 16:13:22 +00:00
|
|
|
self.wallets.append(item)
|
|
|
|
|
self.endInsertRows()
|
2021-04-06 14:13:51 +02:00
|
|
|
|
2022-07-28 18:43:06 +02:00
|
|
|
def remove_wallet(self, path):
|
|
|
|
|
i = 0
|
|
|
|
|
wallets = []
|
|
|
|
|
remove = -1
|
2022-11-11 12:00:07 +01:00
|
|
|
for wallet_name, wallet_path in self.wallets:
|
2022-07-28 18:43:06 +02:00
|
|
|
if wallet_path == path:
|
|
|
|
|
remove = i
|
|
|
|
|
else:
|
2022-11-11 12:00:07 +01:00
|
|
|
wallets.append((wallet_name, wallet_path))
|
2022-07-28 18:43:06 +02:00
|
|
|
i += 1
|
|
|
|
|
|
|
|
|
|
if remove >= 0:
|
|
|
|
|
self.beginRemoveRows(QModelIndex(), i, i)
|
|
|
|
|
self.wallets = wallets
|
|
|
|
|
self.endRemoveRows()
|
|
|
|
|
|
2023-04-27 08:47:02 +00:00
|
|
|
@pyqtSlot(str, result=bool)
|
2022-06-30 10:12:04 +02:00
|
|
|
def wallet_name_exists(self, name):
|
2022-11-11 12:00:07 +01:00
|
|
|
for wallet_name, wallet_path in self.wallets:
|
2022-06-30 10:12:04 +02:00
|
|
|
if name == wallet_name:
|
|
|
|
|
return True
|
|
|
|
|
return False
|
|
|
|
|
|
2022-11-11 12:28:00 +01:00
|
|
|
@pyqtSlot(str)
|
|
|
|
|
def updateWallet(self, path):
|
|
|
|
|
i = 0
|
|
|
|
|
for wallet_name, wallet_path in self.wallets:
|
|
|
|
|
if wallet_path == path:
|
|
|
|
|
mi = self.createIndex(i, i)
|
|
|
|
|
self.dataChanged.emit(mi, mi, self._ROLE_KEYS)
|
|
|
|
|
return
|
|
|
|
|
i += 1
|
|
|
|
|
|
2022-06-21 00:01:30 +02:00
|
|
|
class QEDaemon(AuthMixin, QObject):
|
2021-04-06 14:13:51 +02:00
|
|
|
_logger = get_logger(__name__)
|
2023-01-12 13:09:21 +01:00
|
|
|
|
2022-02-08 10:33:29 +01:00
|
|
|
_available_wallets = None
|
2022-03-10 12:25:18 +01:00
|
|
|
_current_wallet = None
|
2022-09-22 12:43:51 +02:00
|
|
|
_new_wallet_wizard = None
|
2022-10-04 19:47:29 +02:00
|
|
|
_server_connect_wizard = None
|
2022-03-10 12:25:18 +01:00
|
|
|
_path = None
|
2023-02-10 14:27:39 +01:00
|
|
|
_name = None
|
2022-07-06 11:10:00 +02:00
|
|
|
_use_single_password = False
|
|
|
|
|
_password = None
|
2023-02-23 18:20:29 +01:00
|
|
|
_loading = False
|
2022-05-06 15:36:36 +02:00
|
|
|
|
2023-02-22 14:17:57 +01:00
|
|
|
_backendWalletLoaded = pyqtSignal([str], arguments=['password'])
|
|
|
|
|
|
2022-02-08 10:33:29 +01:00
|
|
|
availableWalletsChanged = pyqtSignal()
|
2022-04-05 13:57:42 +02:00
|
|
|
fxChanged = pyqtSignal()
|
2022-09-22 12:43:51 +02:00
|
|
|
newWalletWizardChanged = pyqtSignal()
|
2022-10-04 19:47:29 +02:00
|
|
|
serverConnectWizardChanged = pyqtSignal()
|
2023-02-23 18:20:29 +01:00
|
|
|
loadingChanged = pyqtSignal()
|
2023-03-18 00:52:42 +01:00
|
|
|
requestNewPassword = pyqtSignal()
|
2022-09-22 12:43:51 +02:00
|
|
|
|
2023-02-22 14:17:57 +01:00
|
|
|
walletLoaded = pyqtSignal([str,str], arguments=['name','path'])
|
2023-02-10 14:27:39 +01:00
|
|
|
walletRequiresPassword = pyqtSignal([str,str], arguments=['name','path'])
|
2022-09-22 12:43:51 +02:00
|
|
|
walletOpenError = pyqtSignal([str], arguments=["error"])
|
2022-07-28 18:43:06 +02:00
|
|
|
walletDeleteError = pyqtSignal([str,str], arguments=['code', 'message'])
|
2022-02-08 10:33:29 +01:00
|
|
|
|
2023-03-29 22:09:46 +00:00
|
|
|
def __init__(self, daemon: 'Daemon', parent=None):
|
2023-01-12 13:09:21 +01:00
|
|
|
super().__init__(parent)
|
|
|
|
|
self.daemon = daemon
|
|
|
|
|
self.qefx = QEFX(daemon.fx, daemon.config)
|
2023-02-22 14:17:57 +01:00
|
|
|
|
|
|
|
|
self._backendWalletLoaded.connect(self._on_backend_wallet_loaded)
|
|
|
|
|
|
2023-01-12 13:09:21 +01:00
|
|
|
self._walletdb = QEWalletDB()
|
|
|
|
|
self._walletdb.validPasswordChanged.connect(self.passwordValidityCheck)
|
2023-02-28 14:11:52 +01:00
|
|
|
self._walletdb.walletOpenProblem.connect(self.onWalletOpenProblem)
|
2023-01-12 13:09:21 +01:00
|
|
|
|
2022-05-06 15:36:36 +02:00
|
|
|
@pyqtSlot()
|
|
|
|
|
def passwordValidityCheck(self):
|
2022-07-05 18:30:54 +02:00
|
|
|
if not self._walletdb._validPassword:
|
2023-02-10 14:27:39 +01:00
|
|
|
self.walletRequiresPassword.emit(self._name, self._path)
|
2022-05-06 15:36:36 +02:00
|
|
|
|
2023-02-28 14:04:20 +01:00
|
|
|
@pyqtSlot(str)
|
2023-02-28 14:11:52 +01:00
|
|
|
def onWalletOpenProblem(self, error):
|
2023-02-28 14:04:20 +01:00
|
|
|
self.walletOpenError.emit(error)
|
|
|
|
|
|
2021-04-06 14:13:51 +02:00
|
|
|
@pyqtSlot()
|
2021-04-07 16:48:40 +02:00
|
|
|
@pyqtSlot(str)
|
|
|
|
|
@pyqtSlot(str, str)
|
2023-04-25 13:40:16 +02:00
|
|
|
def loadWallet(self, path=None, password=None):
|
2022-10-31 16:13:22 +00:00
|
|
|
if path is None:
|
2022-10-04 12:34:24 +02:00
|
|
|
self._path = self.daemon.config.get('wallet_path') # command line -w option
|
|
|
|
|
if self._path is None:
|
2023-05-24 17:41:44 +00:00
|
|
|
self._path = self.daemon.config.GUI_LAST_WALLET
|
2022-03-10 14:29:24 +01:00
|
|
|
else:
|
|
|
|
|
self._path = path
|
|
|
|
|
if self._path is None:
|
|
|
|
|
return
|
|
|
|
|
|
2022-07-12 16:49:07 +02:00
|
|
|
self._path = standardize_path(self._path)
|
2023-02-10 14:27:39 +01:00
|
|
|
self._name = os.path.basename(self._path)
|
|
|
|
|
|
2022-03-10 14:29:24 +01:00
|
|
|
self._logger.debug('load wallet ' + str(self._path))
|
2022-05-06 15:36:36 +02:00
|
|
|
|
2023-02-28 14:49:08 +01:00
|
|
|
# map empty string password to None
|
|
|
|
|
if password == '':
|
|
|
|
|
password = None
|
|
|
|
|
|
2022-07-12 16:49:07 +02:00
|
|
|
if not password:
|
|
|
|
|
password = self._password
|
|
|
|
|
|
2023-06-30 10:11:16 +00:00
|
|
|
wallet_already_open = self.daemon.get_wallet(self._path) is not None
|
2022-09-29 13:47:37 +02:00
|
|
|
|
|
|
|
|
if not wallet_already_open:
|
2022-05-06 15:36:36 +02:00
|
|
|
# pre-checks, let walletdb trigger any necessary user interactions
|
|
|
|
|
self._walletdb.path = self._path
|
|
|
|
|
self._walletdb.password = password
|
2022-07-12 16:49:07 +02:00
|
|
|
self._walletdb.verify()
|
2022-05-06 15:36:36 +02:00
|
|
|
if not self._walletdb.ready:
|
2022-03-10 20:35:14 +01:00
|
|
|
return
|
2022-03-10 14:29:24 +01:00
|
|
|
|
2023-02-22 14:17:57 +01:00
|
|
|
def load_wallet_task():
|
2023-02-23 18:20:29 +01:00
|
|
|
self._loading = True
|
|
|
|
|
self.loadingChanged.emit()
|
|
|
|
|
|
2023-02-22 14:17:57 +01:00
|
|
|
try:
|
2023-04-14 10:52:46 +02:00
|
|
|
local_password = password # need this in local scope
|
|
|
|
|
wallet = self.daemon.load_wallet(self._path, local_password)
|
2023-02-22 14:17:57 +01:00
|
|
|
|
|
|
|
|
if wallet is None:
|
|
|
|
|
self._logger.info('could not open wallet')
|
|
|
|
|
self.walletOpenError.emit('could not open wallet')
|
|
|
|
|
return
|
2022-07-06 11:10:00 +02:00
|
|
|
|
2023-04-14 10:52:46 +02:00
|
|
|
if wallet_already_open:
|
|
|
|
|
# wallet already open. daemon.load_wallet doesn't mind, but
|
|
|
|
|
# we need the correct current wallet password below
|
|
|
|
|
local_password = QEWallet.getInstanceFor(wallet).password
|
|
|
|
|
|
2023-05-24 17:41:44 +00:00
|
|
|
if self.daemon.config.WALLET_USE_SINGLE_PASSWORD:
|
2023-04-14 10:52:46 +02:00
|
|
|
self._use_single_password = self.daemon.update_password_for_directory(old_password=local_password, new_password=local_password)
|
|
|
|
|
self._password = local_password
|
2022-07-12 17:34:52 +02:00
|
|
|
self.singlePasswordChanged.emit()
|
2022-07-12 13:51:35 +02:00
|
|
|
self._logger.info(f'use single password: {self._use_single_password}')
|
|
|
|
|
else:
|
|
|
|
|
self._logger.info('use single password disabled by config')
|
2022-07-06 11:10:00 +02:00
|
|
|
|
2022-03-11 13:19:51 +01:00
|
|
|
self.daemon.config.save_last_wallet(wallet)
|
2023-02-22 14:17:57 +01:00
|
|
|
|
2022-09-08 12:19:38 +02:00
|
|
|
run_hook('load_wallet', wallet)
|
2023-02-22 14:17:57 +01:00
|
|
|
|
2023-04-14 10:52:46 +02:00
|
|
|
self._backendWalletLoaded.emit(local_password)
|
2023-02-22 14:17:57 +01:00
|
|
|
except WalletFileException as e:
|
wallet_db version 52: break non-homogeneous multisig wallets
- case 1: in version 4.4.1, 4.4.2, the qml GUI wizard allowed creating multisig wallets with an old_mpk as cosigner.
- case 2: in version 4.4.0, 4.4.1, 4.4.2, the qml GUI wizard allowed creating multisig wallets with mixed xpub/Ypub/Zpub.
The corresponding missing input validation was a bug in the wizard, it was unintended behaviour. Validation was added in d2cf21fc2bcf79f07b7e41178cd3e4ca9e3d9f68. Note however that there might be users who created such wallet files.
Re case 1 wallet files: there is no version of Electrum that allows spending from such a wallet. Coins received at addresses are not burned, however it is technically challenging to spend them. (unless the multisig can spend without needing the old_mpk cosigner in the quorum).
Re case 2 wallet files: it is possible to create a corresponding spending wallet for such a multisig, however it is a bit tricky. The script type for the addresses in such a heterogeneous xpub wallet is based on the xpub_type of the first keystore. So e.g. given a wallet file [Yprv1, Zpub2] it will have sh(wsh()) scripts, and the cosigner should create a wallet file [Ypub1, Zprv2] (same order).
Technically case 2 wallet files could be "fixed" automatically by converting the xpub types as part of a wallet_db upgrade. However if the wallet files also contain seeds, those cannot be converted ("standard" vs "segwit" electrum seed).
Case 1 wallet files are not possible to "fix" automatically as the cosigner using the old_mpk is not bip32 based.
It is unclear if there are *any* users out there affected by this. I suspect for case 1 it is very likely there are none (not many people have pre-2.0 electrum seeds which were never supported as part of a multisig who would also now try to create a multisig using them); for case 2 however there might be.
This commit breaks both case 1 and case 2 wallets: these wallet files can no longer be opened in new Electrum, an error message is shown and the crash reporter opens. If any potential users opt to send crash reports, at least we will know they exist and can help them recover.
2023-05-11 13:48:54 +00:00
|
|
|
self._logger.error(f"load_wallet_task errored opening wallet: {e!r}")
|
2023-02-22 14:17:57 +01:00
|
|
|
self.walletOpenError.emit(str(e))
|
2023-02-23 18:20:29 +01:00
|
|
|
finally:
|
|
|
|
|
self._loading = False
|
|
|
|
|
self.loadingChanged.emit()
|
2023-02-22 14:17:57 +01:00
|
|
|
|
2023-02-23 18:20:29 +01:00
|
|
|
threading.Thread(target=load_wallet_task, daemon=True).start()
|
2023-02-22 14:17:57 +01:00
|
|
|
|
|
|
|
|
@pyqtSlot()
|
|
|
|
|
@pyqtSlot(str)
|
|
|
|
|
def _on_backend_wallet_loaded(self, password = None):
|
|
|
|
|
self._logger.debug('_on_backend_wallet_loaded')
|
2023-06-30 10:11:16 +00:00
|
|
|
wallet = self.daemon.get_wallet(self._path)
|
|
|
|
|
assert wallet is not None
|
2023-02-22 14:17:57 +01:00
|
|
|
self._current_wallet = QEWallet.getInstanceFor(wallet)
|
|
|
|
|
self.availableWallets.updateWallet(self._path)
|
2023-02-28 14:49:08 +01:00
|
|
|
self._current_wallet.password = password if password else None
|
2023-02-22 14:17:57 +01:00
|
|
|
self.walletLoaded.emit(self._name, self._path)
|
|
|
|
|
|
2021-04-06 14:13:51 +02:00
|
|
|
|
2022-07-28 18:43:06 +02:00
|
|
|
@pyqtSlot(QEWallet)
|
|
|
|
|
@pyqtSlot(QEWallet, bool)
|
|
|
|
|
@pyqtSlot(QEWallet, bool, bool)
|
2022-11-11 12:00:07 +01:00
|
|
|
def checkThenDeleteWallet(self, wallet, confirm_requests=False, confirm_balance=False):
|
2022-07-28 18:43:06 +02:00
|
|
|
if wallet.wallet.lnworker:
|
|
|
|
|
lnchannels = wallet.wallet.lnworker.get_channel_objects()
|
2023-01-06 13:13:03 +01:00
|
|
|
if any([channel.get_state() != ChannelState.REDEEMED and not channel.is_backup() for channel in lnchannels.values()]):
|
2022-07-28 18:43:06 +02:00
|
|
|
self.walletDeleteError.emit('unclosed_channels', _('There are still channels that are not fully closed'))
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
num_requests = len(wallet.wallet.get_unpaid_requests())
|
|
|
|
|
if num_requests > 0 and not confirm_requests:
|
|
|
|
|
self.walletDeleteError.emit('unpaid_requests', _('There are still unpaid requests. Really delete?'))
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
c, u, x = wallet.wallet.get_balance()
|
|
|
|
|
if c+u+x > 0 and not wallet.wallet.is_watching_only() and not confirm_balance:
|
|
|
|
|
self.walletDeleteError.emit('balance', _('There are still coins present in this wallet. Really delete?'))
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
self.delete_wallet(wallet)
|
|
|
|
|
|
2023-04-17 18:17:29 +02:00
|
|
|
@auth_protect(message=_('Really delete this wallet?'))
|
2022-06-21 00:01:30 +02:00
|
|
|
def delete_wallet(self, wallet):
|
2022-07-28 18:43:06 +02:00
|
|
|
path = standardize_path(wallet.wallet.storage.path)
|
|
|
|
|
self._logger.debug('deleting wallet with path %s' % path)
|
2022-06-21 14:11:03 +02:00
|
|
|
self._current_wallet = None
|
2022-07-28 18:43:06 +02:00
|
|
|
# TODO walletLoaded signal is confusing
|
2023-03-16 20:23:29 +01:00
|
|
|
self.walletLoaded.emit(None, None)
|
2022-04-04 17:18:04 +02:00
|
|
|
|
2022-07-28 18:43:06 +02:00
|
|
|
if not self.daemon.delete_wallet(path):
|
|
|
|
|
self.walletDeleteError.emit('error', _('Problem deleting wallet'))
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
self.availableWallets.remove_wallet(path)
|
|
|
|
|
|
2023-02-23 18:20:29 +01:00
|
|
|
@pyqtProperty(bool, notify=loadingChanged)
|
|
|
|
|
def loading(self):
|
|
|
|
|
return self._loading
|
|
|
|
|
|
2022-02-08 10:33:29 +01:00
|
|
|
@pyqtProperty(QEWallet, notify=walletLoaded)
|
2021-04-06 14:13:51 +02:00
|
|
|
def currentWallet(self):
|
|
|
|
|
return self._current_wallet
|
|
|
|
|
|
2022-11-11 12:00:07 +01:00
|
|
|
@pyqtProperty(QEWalletListModel, notify=availableWalletsChanged)
|
2021-04-06 14:13:51 +02:00
|
|
|
def availableWallets(self):
|
2022-02-08 10:33:29 +01:00
|
|
|
if not self._available_wallets:
|
2022-11-11 12:00:07 +01:00
|
|
|
self._available_wallets = QEWalletListModel(self.daemon)
|
2022-02-08 10:33:29 +01:00
|
|
|
|
|
|
|
|
return self._available_wallets
|
2022-04-04 13:21:05 +02:00
|
|
|
|
2022-04-05 13:57:42 +02:00
|
|
|
@pyqtProperty(QEFX, notify=fxChanged)
|
|
|
|
|
def fx(self):
|
|
|
|
|
return self.qefx
|
2022-06-30 10:12:04 +02:00
|
|
|
|
2022-07-12 17:34:52 +02:00
|
|
|
singlePasswordChanged = pyqtSignal()
|
|
|
|
|
@pyqtProperty(bool, notify=singlePasswordChanged)
|
|
|
|
|
def singlePasswordEnabled(self):
|
|
|
|
|
return self._use_single_password
|
|
|
|
|
|
|
|
|
|
@pyqtProperty(str, notify=singlePasswordChanged)
|
|
|
|
|
def singlePassword(self):
|
|
|
|
|
return self._password
|
|
|
|
|
|
2022-06-30 10:12:04 +02:00
|
|
|
@pyqtSlot(result=str)
|
|
|
|
|
def suggestWalletName(self):
|
2023-04-05 14:13:40 +00:00
|
|
|
# FIXME why not use util.get_new_wallet_name ?
|
2022-06-30 10:12:04 +02:00
|
|
|
i = 1
|
|
|
|
|
while self.availableWallets.wallet_name_exists(f'wallet_{i}'):
|
|
|
|
|
i = i + 1
|
|
|
|
|
return f'wallet_{i}'
|
|
|
|
|
|
2022-07-06 11:10:00 +02:00
|
|
|
@pyqtSlot()
|
2023-03-18 00:52:42 +01:00
|
|
|
@auth_protect(method='wallet')
|
2022-11-11 12:00:07 +01:00
|
|
|
def startChangePassword(self):
|
2022-07-06 11:10:00 +02:00
|
|
|
if self._use_single_password:
|
|
|
|
|
self.requestNewPassword.emit()
|
|
|
|
|
else:
|
|
|
|
|
self.currentWallet.requestNewPassword.emit()
|
|
|
|
|
|
2023-05-12 10:53:02 +02:00
|
|
|
@pyqtSlot(str, result=bool)
|
2022-11-11 12:00:07 +01:00
|
|
|
def setPassword(self, password):
|
2022-07-06 11:10:00 +02:00
|
|
|
assert self._use_single_password
|
2023-03-03 12:56:02 +01:00
|
|
|
assert password
|
|
|
|
|
if not self.daemon.update_password_for_directory(old_password=self._password, new_password=password):
|
2023-05-12 10:53:02 +02:00
|
|
|
return False
|
2022-07-12 16:49:07 +02:00
|
|
|
self._password = password
|
2023-05-12 10:53:02 +02:00
|
|
|
return True
|
2022-07-12 16:49:07 +02:00
|
|
|
|
2022-09-22 12:43:51 +02:00
|
|
|
@pyqtProperty(QENewWalletWizard, notify=newWalletWizardChanged)
|
|
|
|
|
def newWalletWizard(self):
|
|
|
|
|
if not self._new_wallet_wizard:
|
|
|
|
|
self._new_wallet_wizard = QENewWalletWizard(self)
|
|
|
|
|
|
|
|
|
|
return self._new_wallet_wizard
|
2022-10-04 19:47:29 +02:00
|
|
|
|
|
|
|
|
@pyqtProperty(QEServerConnectWizard, notify=serverConnectWizardChanged)
|
|
|
|
|
def serverConnectWizard(self):
|
|
|
|
|
if not self._server_connect_wizard:
|
|
|
|
|
self._server_connect_wizard = QEServerConnectWizard(self)
|
|
|
|
|
|
|
|
|
|
return self._server_connect_wizard
|
2023-03-29 22:09:46 +00:00
|
|
|
|
|
|
|
|
@pyqtSlot()
|
|
|
|
|
def startNetwork(self):
|
|
|
|
|
self.daemon.start_network()
|