Browse Source

implement wallet password change.

implement wallet delete (though actual wallet file delete is left out still)
patch-4
Sander van Grieken 3 years ago
parent
commit
9243f3b896
  1. 2
      electrum/gui/qml/components/WalletMainView.qml
  2. 22
      electrum/gui/qml/components/Wallets.qml
  3. 115
      electrum/gui/qml/components/controls/PasswordDialog.qml
  4. 31
      electrum/gui/qml/components/main.qml
  5. 2
      electrum/gui/qml/qeapp.py
  6. 5
      electrum/gui/qml/qedaemon.py
  7. 46
      electrum/gui/qml/qewallet.py

2
electrum/gui/qml/components/WalletMainView.qml

@ -6,7 +6,7 @@ import QtQml 2.6
Item {
id: rootItem
property string title: Daemon.currentWallet.name
property string title: Daemon.currentWallet ? Daemon.currentWallet.name : ''
property QtObject menu: Menu {
id: menu

22
electrum/gui/qml/components/Wallets.qml

@ -41,7 +41,8 @@ Pane {
}
function changePassword() {
// TODO: show set password dialog
// trigger dialog via wallet (auth then signal)
Daemon.currentWallet.start_change_password()
}
property QtObject menu: Menu {
@ -58,7 +59,7 @@ Pane {
id: changePasswordComp
MenuItem {
icon.color: 'transparent'
enabled: false
enabled: Daemon.currentWallet // != null
action: Action {
text: qsTr('Change Password');
onTriggered: rootItem.changePassword()
@ -308,6 +309,23 @@ Pane {
}
}
Connections {
target: Daemon.currentWallet
function onRequestNewPassword() { // new wallet password
var dialog = app.passwordDialog.createObject(app,
{
'confirmPassword': true,
'title': qsTr('Enter new password'),
'infotext': qsTr('If you forget your password, you\'ll need to\
restore from seed. Please make sure you have your seed stored safely')
} )
dialog.accepted.connect(function() {
Daemon.currentWallet.set_password(dialog.password)
})
dialog.open()
}
}
Component {
id: share
GenericShareDialog {

115
electrum/gui/qml/components/controls/PasswordDialog.qml

@ -0,0 +1,115 @@
import QtQuick 2.6
import QtQuick.Layouts 1.0
import QtQuick.Controls 2.3
import QtQuick.Controls.Material 2.0
import org.electrum 1.0
Dialog {
id: passworddialog
title: qsTr("Enter Password")
property bool confirmPassword: false
property string password
property string infotext
parent: Overlay.overlay
modal: true
x: (parent.width - width) / 2
y: (parent.height - height) / 2
Overlay.modal: Rectangle {
color: "#aa000000"
}
header: GridLayout {
columns: 2
rowSpacing: 0
Image {
source: "../../../icons/lock.png"
Layout.preferredWidth: constants.iconSizeXLarge
Layout.preferredHeight: constants.iconSizeXLarge
Layout.leftMargin: constants.paddingMedium
Layout.topMargin: constants.paddingMedium
Layout.bottomMargin: constants.paddingMedium
}
Label {
text: title
elide: Label.ElideRight
Layout.fillWidth: true
topPadding: constants.paddingXLarge
bottomPadding: constants.paddingXLarge
font.bold: true
font.pixelSize: constants.fontSizeMedium
}
Rectangle {
Layout.columnSpan: 2
Layout.fillWidth: true
Layout.leftMargin: constants.paddingXXSmall
Layout.rightMargin: constants.paddingXXSmall
height: 1
color: Qt.rgba(0,0,0,0.5)
}
}
ColumnLayout {
width: parent.width
InfoTextArea {
visible: infotext
text: infotext
Layout.preferredWidth: password_layout.width
}
GridLayout {
id: password_layout
columns: 2
Layout.fillWidth: true
Layout.margins: constants.paddingXXLarge
Label {
text: qsTr('Password')
}
TextField {
id: pw_1
echoMode: TextInput.Password
}
Label {
text: qsTr('Password (again)')
visible: confirmPassword
}
TextField {
id: pw_2
echoMode: TextInput.Password
visible: confirmPassword
}
}
RowLayout {
Layout.alignment: Qt.AlignHCenter
Layout.topMargin: constants.paddingXXLarge
Button {
text: qsTr("Ok")
enabled: confirmPassword ? pw_1.text == pw_2.text : true
onClicked: {
password = pw_1.text
passworddialog.accept()
}
}
Button {
text: qsTr("Cancel")
onClicked: {
passworddialog.reject()
}
}
}
}
}

31
electrum/gui/qml/components/main.qml

@ -171,6 +171,14 @@ ApplicationWindow
}
}
property alias passwordDialog: _passwordDialog
Component {
id: _passwordDialog
PasswordDialog {
onClosed: destroy()
}
}
NotificationPopup {
id: notificationPopup
}
@ -225,14 +233,23 @@ ApplicationWindow
Connections {
target: Daemon.currentWallet
function onAuthRequired() {
var dialog = app.messageDialog.createObject(app, {'text': 'Auth placeholder', 'yesno': true})
dialog.yesClicked.connect(function() {
if (Daemon.currentWallet.verify_password('')) {
// wallet has no password
Daemon.currentWallet.authProceed()
})
dialog.noClicked.connect(function() {
Daemon.currentWallet.authCancel()
})
dialog.open()
} else {
var dialog = app.passwordDialog.createObject(app, {'title': qsTr('Enter current password')})
dialog.accepted.connect(function() {
if (Daemon.currentWallet.verify_password(dialog.password)) {
Daemon.currentWallet.authProceed()
} else {
Daemon.currentWallet.authCancel()
}
})
dialog.rejected.connect(function() {
Daemon.currentWallet.authCancel()
})
dialog.open()
}
}
}

2
electrum/gui/qml/qeapp.py

@ -52,6 +52,8 @@ class QEAppController(QObject):
def on_wallet_loaded(self):
qewallet = self._qedaemon.currentWallet
if not qewallet:
return
# attach to the wallet user notification events
# connect only once
try:

5
electrum/gui/qml/qedaemon.py

@ -152,7 +152,12 @@ class QEDaemon(AuthMixin, QObject):
path = wallet.wallet.storage.path
self._logger.debug('Ok to delete wallet with path %s' % path)
# TODO checks, e.g. existing LN channels, unpaid requests, etc
self._logger.debug('Not deleting yet, just unloading for now')
# TODO actually delete
# TODO walletLoaded signal is confusing
self.daemon.stop_wallet(path)
self._current_wallet = None
self.walletLoaded.emit()
@pyqtProperty('QString')
def path(self):

46
electrum/gui/qml/qewallet.py

@ -7,9 +7,10 @@ import threading
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, QUrl, QTimer
from electrum.i18n import _
from electrum.util import register_callback, Satoshis, format_time, parse_max_spend
from electrum.util import register_callback, Satoshis, format_time, parse_max_spend, InvalidPassword
from electrum.logging import get_logger
from electrum.wallet import Wallet, Abstract_Wallet
from electrum.storage import StorageEncryptionVersion
from electrum import bitcoin
from electrum.transaction import PartialTxOutput
from electrum.invoices import (Invoice, InvoiceError,
@ -331,7 +332,7 @@ class QEWallet(AuthMixin, QObject):
self.wallet.init_lightning(password=None) # TODO pass password if needed
self.isLightningChanged.emit()
@pyqtSlot('QString', int, int, bool)
@pyqtSlot(str, int, int, bool)
def send_onchain(self, address, amount, fee=None, rbf=False):
self._logger.info('send_onchain: %s %d' % (address,amount))
coins = self.wallet.get_spendable_coins(None)
@ -437,9 +438,9 @@ class QEWallet(AuthMixin, QObject):
return req_key, addr
@pyqtSlot(QEAmount, 'QString', int)
@pyqtSlot(QEAmount, 'QString', int, bool)
@pyqtSlot(QEAmount, 'QString', int, bool, bool)
@pyqtSlot(QEAmount, str, int)
@pyqtSlot(QEAmount, str, int, bool)
@pyqtSlot(QEAmount, str, int, bool, bool)
def create_request(self, amount: QEAmount, message: str, expiration: int, is_lightning: bool = False, ignore_gap: bool = False):
try:
if is_lightning:
@ -463,29 +464,52 @@ class QEWallet(AuthMixin, QObject):
self._requestModel.add_invoice(self.wallet.get_request(key))
self.requestCreateSuccess.emit()
@pyqtSlot('QString')
@pyqtSlot(str)
def delete_request(self, key: str):
self._logger.debug('delete req %s' % key)
self.wallet.delete_request(key)
self._requestModel.delete_invoice(key)
@pyqtSlot('QString', result='QVariant')
@pyqtSlot(str, result='QVariant')
def get_request(self, key: str):
return self._requestModel.get_model_invoice(key)
@pyqtSlot('QString')
@pyqtSlot(str)
def delete_invoice(self, key: str):
self._logger.debug('delete inv %s' % key)
self.wallet.delete_invoice(key)
self._invoiceModel.delete_invoice(key)
@pyqtSlot('QString', result='QVariant')
@pyqtSlot(str, result='QVariant')
def get_invoice(self, key: str):
return self._invoiceModel.get_model_invoice(key)
@pyqtSlot(str)
@pyqtSlot(str, result=bool)
def verify_password(self, password):
try:
self.wallet.storage.check_password(password)
return True
except InvalidPassword as e:
return False
requestNewPassword = pyqtSignal()
@pyqtSlot()
@auth_protect
def start_change_password(self):
self.requestNewPassword.emit()
@pyqtSlot(str)
def set_password(self, password):
storage = self.wallet.storage
# HW wallet not supported yet
if storage.is_encrypted_with_hw_device():
return
self._logger.debug('Ok to set password for wallet with path %s' % storage.path)
# TODO
if password:
enc_version = StorageEncryptionVersion.USER_PASSWORD
else:
enc_version = StorageEncryptionVersion.PLAINTEXT
storage.set_password(password, enc_version=enc_version)
self.wallet.save_db()

Loading…
Cancel
Save