From cec206ec8d4267e2cc7e987a2dcd9762720d414f Mon Sep 17 00:00:00 2001 From: stoffu Date: Fri, 17 Nov 2017 10:16:35 +0900 Subject: [PATCH 1/2] Refactor wallet password dialog --- main.qml | 146 ++++++++++++++++++++---------------------- wizard/WizardMain.qml | 2 +- 2 files changed, 69 insertions(+), 79 deletions(-) diff --git a/main.qml b/main.qml index 944eefa2..6b55c76a 100644 --- a/main.qml +++ b/main.qml @@ -53,7 +53,7 @@ ApplicationWindow { property var currentWallet; property var transaction; property var transactionDescription; - property alias password : passwordDialog.password + property var walletPassword property bool isNewWallet: false property int restoreHeight:0 property bool daemonSynced: false @@ -166,7 +166,7 @@ ApplicationWindow { persistentSettings.restore_height = 0 restoreHeight = 0; persistentSettings.is_recovering = false - appWindow.password = "" + walletPassword = "" fileDialog.open(); } @@ -226,7 +226,7 @@ ApplicationWindow { wallet_path = moneroAccountsDir + wallet_path; // console.log("opening wallet at: ", wallet_path, "with password: ", appWindow.password); console.log("opening wallet at: ", wallet_path, ", testnet: ", persistentSettings.testnet); - walletManager.openWalletAsync(wallet_path, appWindow.password, + walletManager.openWalletAsync(wallet_path, walletPassword, persistentSettings.testnet); } @@ -338,25 +338,25 @@ ApplicationWindow { walletName = usefulName(wallet.path) console.log(">>> wallet opened: " + wallet) if (wallet.status !== Wallet.Status_Ok) { - if (appWindow.password === '') { - console.error("Error opening wallet with empty password: ", wallet.errorString); - console.log("closing wallet async : " + wallet.address) - closeWallet(); - // try to open wallet with password; - passwordDialog.open(walletName); - } else { - // opening with password but password doesn't match - console.error("Error opening wallet with password: ", wallet.errorString); - - informationPopup.title = qsTr("Error") + translationManager.emptyString; - informationPopup.text = qsTr("Couldn't open wallet: ") + wallet.errorString; - informationPopup.icon = StandardIcon.Critical - console.log("closing wallet async : " + wallet.address) - closeWallet(); - informationPopup.open() - informationPopup.onCloseCallback = function() { - passwordDialog.open(walletName) - } + passwordDialog.onAcceptedCallback = function() { + walletPassword = passwordDialog.password; + appWindow.initialize(); + } + passwordDialog.onRejectedCallback = function() { + walletPassword = ""; + //appWindow.enableUI(false) + rootItem.state = "wizard"; + } + // opening with password but password doesn't match + console.error("Error opening wallet with password: ", wallet.errorString); + informationPopup.title = qsTr("Error") + translationManager.emptyString; + informationPopup.text = qsTr("Couldn't open wallet: ") + wallet.errorString; + informationPopup.icon = StandardIcon.Critical + console.log("closing wallet async : " + wallet.address) + closeWallet(); + informationPopup.open() + informationPopup.onCloseCallback = function() { + passwordDialog.open(walletName) } return; } @@ -951,7 +951,14 @@ ApplicationWindow { rootItem.state = "wizard" } else { rootItem.state = "normal" + passwordDialog.onAcceptedCallback = function() { + walletPassword = passwordDialog.password; initialize(persistentSettings); + } + passwordDialog.onRejectedCallback = function() { + rootItem.state = "wizard" + } + passwordDialog.open(usefulName(walletPath())) } checkUpdates(); @@ -1013,8 +1020,8 @@ ApplicationWindow { id: transactionConfirmationPopup onAccepted: { close(); - transactionConfirmationPasswordDialog.onAcceptedCallback = function() { - if(appWindow.password === transactionConfirmationPasswordDialog.password){ + passwordDialog.onAcceptedCallback = function() { + if(walletPassword === passwordDialog.password){ // Save transaction to file if view only wallet if(viewOnly) { saveTxDialog.open(); @@ -1026,15 +1033,12 @@ ApplicationWindow { informationPopup.text = qsTr("Wrong password"); informationPopup.open() informationPopup.onCloseCallback = function() { - transactionConfirmationPasswordDialog.open() + passwordDialog.open() } } - transactionConfirmationPasswordDialog.password = "" } - transactionConfirmationPasswordDialog.onRejectedCallback = function() { - transactionConfirmationPasswordDialog.password = "" - } - transactionConfirmationPasswordDialog.open() + passwordDialog.onRejectedCallback = null; + passwordDialog.open() } } @@ -1072,7 +1076,15 @@ ApplicationWindow { console.log(moneroAccountsDir) console.log(fileDialog.fileUrl) console.log(persistentSettings.wallet_path) - initialize(); + passwordDialog.onAcceptedCallback = function() { + walletPassword = passwordDialog.password; + initialize(); + } + passwordDialog.onRejectedCallback = function() { + console.log("Canceled") + rootItem.state = "wizard"; + } + passwordDialog.open(usefulName(walletPath())); } onRejected: { console.log("Canceled") @@ -1138,21 +1150,6 @@ ApplicationWindow { visible: false z: parent.z + 1 anchors.fill: parent - onAccepted: { - appWindow.initialize(); - } - onRejected: { - //appWindow.enableUI(false) - rootItem.state = "wizard" - } - - } - - PasswordDialog { - id: transactionConfirmationPasswordDialog - z: parent.z + 1 - visible:false - anchors.fill: parent property var onAcceptedCallback property var onRejectedCallback onAccepted: { @@ -1165,37 +1162,6 @@ ApplicationWindow { } } - PasswordDialog { - id: settingsPasswordDialog - z: parent.z + 1 - visible:false - anchors.fill: parent - onAccepted: { - if(appWindow.password === settingsPasswordDialog.password){ - if(currentWallet.seedLanguage == "") { - console.log("No seed language set. Using English as default"); - currentWallet.setSeedLanguage("English"); - } - - // Load keys page - middlePanel.state = "Keys" - - } else { - informationPopup.title = qsTr("Error") + translationManager.emptyString; - informationPopup.text = qsTr("Wrong password"); - informationPopup.open() - informationPopup.onCloseCallback = function() { - settingsPasswordDialog.open() - } - } - - settingsPasswordDialog.password = "" - } - onRejected: { - appWindow.showPageRequest("Settings"); - } - } - DaemonManagerDialog { id: daemonManagerDialog onRejected: { @@ -1278,7 +1244,31 @@ ApplicationWindow { onMiningClicked: { middlePanel.state = "Mining"; if(isMobile) hideMenu(); updateBalance(); } onSignClicked: { middlePanel.state = "Sign"; if(isMobile) hideMenu(); updateBalance(); } onSettingsClicked: { middlePanel.state = "Settings"; if(isMobile) hideMenu(); updateBalance(); } - onKeysClicked: { settingsPasswordDialog.open(); if(isMobile) hideMenu(); updateBalance(); } + onKeysClicked: { + passwordDialog.onAcceptedCallback = function() { + if(walletPassword === passwordDialog.password){ + if(currentWallet.seedLanguage == "") { + console.log("No seed language set. Using English as default"); + currentWallet.setSeedLanguage("English"); + } + // Load keys page + middlePanel.state = "Keys" + } else { + informationPopup.title = qsTr("Error") + translationManager.emptyString; + informationPopup.text = qsTr("Wrong password"); + informationPopup.open() + informationPopup.onCloseCallback = function() { + passwordDialog.open() + } + } + } + passwordDialog.onRejectedCallback = function() { + appWindow.showPageRequest("Settings"); + } + passwordDialog.open(); + if(isMobile) hideMenu(); + updateBalance(); + } } RightPanel { diff --git a/wizard/WizardMain.qml b/wizard/WizardMain.qml index d5c9eb11..f792b383 100644 --- a/wizard/WizardMain.qml +++ b/wizard/WizardMain.qml @@ -226,7 +226,7 @@ ColumnLayout { m_wallet.setPassword(settings.wallet_password); // Store password in session to be able to use password protected functions (e.g show seed) - appWindow.password = settings.wallet_password + appWindow.walletPassword = settings.wallet_password // saving wallet_filename; settings['wallet_filename'] = new_wallet_filename; From cf488f4406bd9e6f8726a180f56aff017408a706 Mon Sep 17 00:00:00 2001 From: stoffu Date: Fri, 22 Sep 2017 23:25:25 +0900 Subject: [PATCH 2/2] Allow password to be changed --- components/NewPasswordDialog.qml | 254 +++++++++++++++++++++++++++++++ main.qml | 23 +++ pages/Settings.qml | 26 ++++ qml.qrc | 1 + 4 files changed, 304 insertions(+) create mode 100644 components/NewPasswordDialog.qml diff --git a/components/NewPasswordDialog.qml b/components/NewPasswordDialog.qml new file mode 100644 index 00000000..414a225d --- /dev/null +++ b/components/NewPasswordDialog.qml @@ -0,0 +1,254 @@ +// Copyright (c) 2017, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import QtQuick 2.0 +import QtQuick.Controls 1.4 +import QtQuick.Dialogs 1.2 +import QtQuick.Layouts 1.1 +import QtQuick.Controls.Styles 1.4 +import QtQuick.Window 2.0 + +import "../components" as MoneroComponents + +Item { + id: root + visible: false + Rectangle { + id: bg + z: parent.z + 1 + anchors.fill: parent + color: "white" + opacity: 0.9 + } + + property alias password: passwordInput1.text + + // same signals as Dialog has + signal accepted() + signal rejected() + signal closeCallback() + + function open() { + leftPanel.enabled = false + middlePanel.enabled = false + titleBar.enabled = false + show(); + root.visible = true; + passwordInput1.text = ""; + passwordInput2.text = ""; + passwordInput1.focus = true + } + + function close() { + leftPanel.enabled = true + middlePanel.enabled = true + titleBar.enabled = true + root.visible = false; + closeCallback(); + } + + // TODO: implement without hardcoding sizes + width: 480 + height: 360 + + // Make window draggable + MouseArea { + anchors.fill: parent + property point lastMousePos: Qt.point(0, 0) + onPressed: { lastMousePos = Qt.point(mouseX, mouseY); } + onMouseXChanged: root.x += (mouseX - lastMousePos.x) + onMouseYChanged: root.y += (mouseY - lastMousePos.y) + } + + ColumnLayout { + z: bg.z + 1 + id: mainLayout + spacing: 10 + anchors { fill: parent; margins: 35 * scaleRatio } + + ColumnLayout { + id: column + //anchors {fill: parent; margins: 16 } + Layout.alignment: Qt.AlignHCenter + + Label { + text: qsTr("Please enter new password") + Layout.alignment: Qt.AlignHCenter + Layout.columnSpan: 2 + Layout.fillWidth: true + horizontalAlignment: Text.AlignHCenter + font.pixelSize: 18 * scaleRatio + font.family: "Arial" + color: "#555555" + } + + TextField { + id : passwordInput1 + Layout.fillWidth: true + Layout.alignment: Qt.AlignHCenter + Layout.maximumWidth: 400 * scaleRatio + horizontalAlignment: TextInput.AlignHCenter + verticalAlignment: TextInput.AlignVCenter + font.family: "Arial" + font.pixelSize: 32 * scaleRatio + echoMode: TextInput.Password + KeyNavigation.tab: passwordInput2 + + style: TextFieldStyle { + renderType: Text.NativeRendering + textColor: "#35B05A" + passwordCharacter: "•" + // no background + background: Rectangle { + radius: 0 + border.width: 0 + } + } + Keys.onEscapePressed: { + root.close() + root.rejected() + } + } + + // underline + Rectangle { + height: 1 + color: "#DBDBDB" + Layout.fillWidth: true + Layout.alignment: Qt.AlignHCenter + anchors.bottomMargin: 3 + Layout.maximumWidth: passwordInput1.width + } + // padding + Rectangle { + Layout.fillWidth: true + Layout.alignment: Qt.AlignHCenter + height: 10 + opacity: 0 + color: "black" + } + + Label { + text: qsTr("Please confirm new password") + Layout.alignment: Qt.AlignHCenter + Layout.columnSpan: 2 + Layout.fillWidth: true + horizontalAlignment: Text.AlignHCenter + font.pixelSize: 18 * scaleRatio + font.family: "Arial" + color: "#555555" + } + + TextField { + id : passwordInput2 + Layout.fillWidth: true + Layout.alignment: Qt.AlignHCenter + Layout.maximumWidth: 400 * scaleRatio + horizontalAlignment: TextInput.AlignHCenter + verticalAlignment: TextInput.AlignVCenter + font.family: "Arial" + font.pixelSize: 32 * scaleRatio + echoMode: TextInput.Password + KeyNavigation.tab: okButton + + style: TextFieldStyle { + renderType: Text.NativeRendering + textColor: "#35B05A" + passwordCharacter: "•" + // no background + background: Rectangle { + radius: 0 + border.width: 0 + } + } + Keys.onReturnPressed: { + if (passwordInput1.text === passwordInput2.text) { + root.close() + root.accepted() + } + } + Keys.onEscapePressed: { + root.close() + root.rejected() + } + } + + // underline + Rectangle { + height: 1 + color: "#DBDBDB" + Layout.fillWidth: true + Layout.alignment: Qt.AlignHCenter + anchors.bottomMargin: 3 + Layout.maximumWidth: passwordInput1.width + } + // padding + Rectangle { + Layout.fillWidth: true + Layout.alignment: Qt.AlignHCenter + height: 10 + opacity: 0 + color: "black" + } + } + // Ok/Cancel buttons + RowLayout { + id: buttons + spacing: 60 * scaleRatio + Layout.alignment: Qt.AlignHCenter + + MoneroComponents.StandardButton { + id: cancelButton + shadowReleasedColor: "#FF4304" + shadowPressedColor: "#B32D00" + releasedColor: "#FF6C3C" + pressedColor: "#FF4304" + text: qsTr("Cancel") + translationManager.emptyString + KeyNavigation.tab: passwordInput1 + onClicked: { + root.close() + root.rejected() + } + } + MoneroComponents.StandardButton { + id: okButton + shadowReleasedColor: "#FF4304" + shadowPressedColor: "#B32D00" + releasedColor: "#FF6C3C" + pressedColor: "#FF4304" + text: qsTr("Continue") + KeyNavigation.tab: cancelButton + enabled: passwordInput1.text === passwordInput2.text + onClicked: { + root.close() + root.accepted() + } + } + } + } +} diff --git a/main.qml b/main.qml index 6b55c76a..387d1b5d 100644 --- a/main.qml +++ b/main.qml @@ -1162,6 +1162,29 @@ ApplicationWindow { } } + NewPasswordDialog { + id: newPasswordDialog + z: parent.z + 1 + visible:false + anchors.fill: parent + onAccepted: { + if (currentWallet.setPassword(newPasswordDialog.password)) { + appWindow.walletPassword = newPasswordDialog.password; + informationPopup.title = qsTr("Information") + translationManager.emptyString; + informationPopup.text = qsTr("Password changed successfully") + translationManager.emptyString; + informationPopup.icon = StandardIcon.Information; + } else { + informationPopup.title = qsTr("Error") + translationManager.emptyString; + informationPopup.text = qsTr("Error: ") + currentWallet.errorString; + informationPopup.icon = StandardIcon.Critical; + } + informationPopup.onCloseCallback = null; + informationPopup.open(); + } + onRejected: { + } + } + DaemonManagerDialog { id: daemonManagerDialog onRejected: { diff --git a/pages/Settings.qml b/pages/Settings.qml index a83b53ee..61844b4f 100644 --- a/pages/Settings.qml +++ b/pages/Settings.qml @@ -164,6 +164,32 @@ Rectangle { } } } + + StandardButton { + id: changePasswordButton + text: qsTr("Change password") + translationManager.emptyString + shadowReleasedColor: "#FF4304" + shadowPressedColor: "#B32D00" + releasedColor: "#FF6C3C" + pressedColor: "#FF4304" + onClicked: { + passwordDialog.onAcceptedCallback = function() { + if(appWindow.walletPassword === passwordDialog.password){ + newPasswordDialog.open() + } else { + informationPopup.title = qsTr("Error") + translationManager.emptyString; + informationPopup.text = qsTr("Wrong password"); + informationPopup.open() + informationPopup.onCloseCallback = function() { + changePasswordDialog.open() + } + passwordDialog.open() + } + } + passwordDialog.onRejectedCallback = null; + passwordDialog.open() + } + } } RowLayout { diff --git a/qml.qrc b/qml.qrc index b7432b56..cd373505 100644 --- a/qml.qrc +++ b/qml.qrc @@ -134,6 +134,7 @@ pages/TxKey.qml components/IconButton.qml components/PasswordDialog.qml + components/NewPasswordDialog.qml components/ProcessingSplash.qml components/ProgressBar.qml components/StandardDialog.qml