1
0

qml: OpenWalletDialog: load any wallet if password matches

If the user has wallets with different passwords (non-unified pw) and
enters a password on startup that fails to unlock the recently used
wallet this change will automatically open any other wallet if there
is another wallet that can be unlocked with this password.
This commit is contained in:
f321x
2025-12-17 11:02:26 +01:00
parent ba379b7da4
commit aee0f8fb54
5 changed files with 52 additions and 2 deletions

View File

@@ -12,6 +12,7 @@ ElDialog {
property string name
property string path
property bool isStartup
property bool _invalidPassword: false
property bool _unlockClicked: false
@@ -40,7 +41,7 @@ ElDialog {
InfoTextArea {
id: notice
text: Daemon.singlePasswordEnabled || !Daemon.currentWallet
text: Daemon.singlePasswordEnabled || isStartup
? qsTr('Please enter password')
: qsTr('Wallet <b>%1</b> requires password to unlock').arg(name)
iconStyle: InfoTextArea.IconStyle.Warn
@@ -94,9 +95,39 @@ ElDialog {
Daemon.loadWallet(openwalletdialog.path, password.text)
}
function maybeUnlockAnyOtherWallet() {
// try to open any other wallet with the password the user entered, hack to improve ux for
// users with non-unified wallet password.
// we should only fall back to opening a random wallet if:
// - the user did not select a specific wallet, otherwise this is confusing
// - there can be more than one password, otherwise this scan would be pointless
if (Daemon.availableWallets.rowCount() <= 1 || password.text === '') {
return false
}
if (Config.walletDidUseSinglePassword) {
// the last time the wallet was unlocked all wallets used the same password.
// trying to decrypt all of them now is most probably useless.
return false
}
if (!openwalletdialog.isStartup) {
return false // this dialog got opened because the user clicked on a specific wallet
}
let wallet_paths = Daemon.getWalletsUnlockableWithPassword(password.text)
if (wallet_paths && wallet_paths.length > 0) {
console.log('could not unlock recent wallet, falling back to: ' + wallet_paths[0])
Daemon.loadWallet(wallet_paths[0], password.text)
return true
}
return false
}
Connections {
target: Daemon
function onWalletRequiresPassword() {
if (maybeUnlockAnyOtherWallet()) {
password.text = '' // reset pw so we cannot end up in a loop
return
}
console.log('invalid password')
_invalidPassword = true
password.tf.forceActiveFocus()

View File

@@ -634,12 +634,18 @@ ApplicationWindow
}
property var _opendialog: undefined
property var _opendialog_startup: true
function showOpenWalletDialog(name, path) {
if (_opendialog == undefined) {
_opendialog = openWalletDialog.createObject(app, { name: name, path: path })
_opendialog = openWalletDialog.createObject(app, {
name: name,
path: path,
isStartup: _opendialog_startup,
})
_opendialog.closed.connect(function() {
_opendialog = undefined
_opendialog_startup = false
})
_opendialog.open()
}

View File

@@ -340,6 +340,16 @@ class QEConfig(AuthMixin, QObject):
"""
return self.config.WALLET_SHOULD_USE_SINGLE_PASSWORD
walletDidUseSinglePasswordChanged = pyqtSignal()
@pyqtProperty(bool, notify=walletDidUseSinglePasswordChanged)
def walletDidUseSinglePassword(self):
"""
Allows to guess if this is a unified password instance without having
unlocked any wallet yet. Might be out of sync e.g. if wallet files get copied manually.
"""
# TODO: consider removing once encrypted wallet file headers are available
return self.config.WALLET_DID_USE_SINGLE_PASSWORD
@pyqtSlot('qint64', result=str)
@pyqtSlot(QEAmount, result=str)
def formatSatsForEditing(self, satoshis):

View File

@@ -237,6 +237,7 @@ class QEDaemon(AuthMixin, QObject):
self._logger.info(f'use single password: {self._use_single_password}')
else:
self._logger.info('use single password disabled by config')
self.daemon.config.WALLET_DID_USE_SINGLE_PASSWORD = self._use_single_password
run_hook('load_wallet', wallet)

View File

@@ -676,6 +676,8 @@ class SimpleConfig(Logger):
WALLET_UNCONF_UTXO_FREEZE_THRESHOLD_SAT = ConfigVar('unconf_utxo_freeze_threshold', default=5_000, type_=int)
WALLET_PAYREQ_EXPIRY_SECONDS = ConfigVar('request_expiry', default=invoices.PR_DEFAULT_EXPIRATION_WHEN_CREATING, type_=int)
WALLET_SHOULD_USE_SINGLE_PASSWORD = ConfigVar('should_use_single_password', default=False, type_=bool)
# TODO: consider removing WALLET_DID_USE_SINGLE_PASSWORD once encrypted wallet file headers are available
WALLET_DID_USE_SINGLE_PASSWORD = ConfigVar('did_use_single_password', default=False, type_=bool)
# note: 'use_change' and 'multiple_change' are per-wallet settings
WALLET_SEND_CHANGE_TO_LIGHTNING = ConfigVar(
'send_change_to_lightning', default=False, type_=bool,