aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--components/NewPasswordDialog.qml287
-rw-r--r--components/PassphraseDialog.qml321
-rw-r--r--components/PasswordDialog.qml254
-rw-r--r--js/Utils.js19
-rw-r--r--main.qml49
-rw-r--r--monero-wallet-gui.pro9
-rw-r--r--oshelper.cpp35
-rw-r--r--oshelper.h1
-rw-r--r--pages/settings/SettingsWallet.qml2
-rw-r--r--qml.qrc2
-rw-r--r--src/qt/macoshelper.h40
-rw-r--r--src/qt/macoshelper.mm49
-rw-r--r--wizard/WizardController.qml8
13 files changed, 366 insertions, 710 deletions
diff --git a/components/NewPasswordDialog.qml b/components/NewPasswordDialog.qml
deleted file mode 100644
index 3f3c4f38..00000000
--- a/components/NewPasswordDialog.qml
+++ /dev/null
@@ -1,287 +0,0 @@
-// Copyright (c) 2014-2019, 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.9
-import QtQuick.Controls 2.0
-import QtQuick.Dialogs 1.2
-import QtQuick.Layouts 1.1
-import QtQuick.Controls.Styles 1.4
-import QtQuick.Window 2.0
-import FontAwesome 1.0
-
-import "../components" as MoneroComponents
-
-Item {
- id: root
- visible: false
- z: parent.z + 2
-
- property bool isHidden: true
- property alias password: passwordInput1.text
-
- // same signals as Dialog has
- signal accepted()
- signal rejected()
- signal closeCallback()
-
- function open() {
- isHidden = true
- passwordInput1.echoMode = TextInput.Password;
- passwordInput2.echoMode = TextInput.Password;
- inactiveOverlay.visible = true
- leftPanel.enabled = false
- middlePanel.enabled = false
- titleBar.state = "essentials"
- root.visible = true;
- passwordInput1.text = "";
- passwordInput2.text = "";
- passwordInput1.focus = true
- }
-
- function close() {
- inactiveOverlay.visible = false
- leftPanel.enabled = true
- middlePanel.enabled = true
- titleBar.state = "default"
- root.visible = false;
- closeCallback();
- }
-
- function toggleIsHidden() {
- passwordInput1.echoMode = isHidden ? TextInput.Normal : TextInput.Password;
- passwordInput2.echoMode = isHidden ? TextInput.Normal : TextInput.Password;
- isHidden = !isHidden;
- }
-
- // TODO: implement without hardcoding sizes
- width: 480
- height: 360
-
- ColumnLayout {
- z: inactiveOverlay.z + 1
- id: mainLayout
- spacing: 10
- anchors { fill: parent; margins: 35 }
-
- ColumnLayout {
- id: column
-
- Layout.fillWidth: true
- Layout.alignment: Qt.AlignHCenter
- Layout.maximumWidth: 400
-
- Label {
- text: qsTr("Please enter new password") + translationManager.emptyString
- Layout.fillWidth: true
-
- font.pixelSize: 16
- font.family: MoneroComponents.Style.fontLight.name
-
- color: MoneroComponents.Style.defaultFontColor
- }
-
- TextField {
- id : passwordInput1
- Layout.topMargin: 6
- Layout.fillWidth: true
- horizontalAlignment: TextInput.AlignLeft
- verticalAlignment: TextInput.AlignVCenter
- font.family: MoneroComponents.Style.fontLight.name
- font.pixelSize: 24
- echoMode: TextInput.Password
- bottomPadding: 10
- leftPadding: 10
- topPadding: 10
- color: MoneroComponents.Style.defaultFontColor
- selectionColor: MoneroComponents.Style.textSelectionColor
- selectedTextColor: MoneroComponents.Style.textSelectedColor
- KeyNavigation.tab: passwordInput2
-
- background: Rectangle {
- radius: 2
- border.color: MoneroComponents.Style.inputBorderColorInActive
- border.width: 1
- color: MoneroComponents.Style.blackTheme ? "black" : "#A9FFFFFF"
-
- MoneroComponents.Label {
- fontSize: 20
- text: isHidden ? FontAwesome.eye : FontAwesome.eyeSlash
- opacity: 0.7
- fontFamily: FontAwesome.fontFamily
- anchors.right: parent.right
- anchors.rightMargin: 15
- anchors.verticalCenter: parent.verticalCenter
- anchors.verticalCenterOffset: 1
-
- MouseArea {
- anchors.fill: parent
- cursorShape: Qt.PointingHandCursor
- hoverEnabled: true
- onClicked: {
- toggleIsHidden()
- }
- onEntered: {
- parent.opacity = 0.9
- parent.fontSize = 24
- }
- onExited: {
- parent.opacity = 0.7
- parent.fontSize = 20
- }
- }
- }
- }
-
- Keys.onEscapePressed: {
- root.close()
- root.rejected()
- }
- }
-
- // padding
- Rectangle {
- Layout.fillWidth: true
- Layout.alignment: Qt.AlignHCenter
- height: 10
- opacity: 0
- color: "black"
- }
-
- Label {
- text: qsTr("Please confirm new password") + translationManager.emptyString
- Layout.fillWidth: true
-
- font.pixelSize: 16
- font.family: MoneroComponents.Style.fontLight.name
-
- color: MoneroComponents.Style.defaultFontColor
- }
-
- TextField {
- id : passwordInput2
- Layout.topMargin: 6
- Layout.fillWidth: true
- horizontalAlignment: TextInput.AlignLeft
- verticalAlignment: TextInput.AlignVCenter
- font.family: MoneroComponents.Style.fontLight.name
- font.pixelSize: 24
- echoMode: TextInput.Password
- KeyNavigation.tab: okButton
- bottomPadding: 10
- leftPadding: 10
- topPadding: 10
- color: MoneroComponents.Style.defaultFontColor
- selectionColor: MoneroComponents.Style.textSelectionColor
- selectedTextColor: MoneroComponents.Style.textSelectedColor
-
- background: Rectangle {
- radius: 2
- border.color: MoneroComponents.Style.inputBorderColorInActive
- border.width: 1
- color: MoneroComponents.Style.blackTheme ? "black" : "#A9FFFFFF"
-
- MoneroComponents.Label {
- fontSize: 20
- text: isHidden ? FontAwesome.eye : FontAwesome.eyeSlash
- opacity: 0.7
- fontFamily: FontAwesome.fontFamily
- anchors.right: parent.right
- anchors.rightMargin: 15
- anchors.verticalCenter: parent.verticalCenter
- anchors.verticalCenterOffset: 1
-
- MouseArea {
- anchors.fill: parent
- cursorShape: Qt.PointingHandCursor
- hoverEnabled: true
- onClicked: {
- toggleIsHidden()
- }
- onEntered: {
- parent.opacity = 0.9
- parent.fontSize = 24
- }
- onExited: {
- parent.opacity = 0.7
- parent.fontSize = 20
- }
- }
- }
- }
-
- Keys.onReturnPressed: {
- if (passwordInput1.text === passwordInput2.text) {
- root.close()
- root.accepted()
- }
- }
- Keys.onEscapePressed: {
- root.close()
- root.rejected()
- }
- }
-
- // padding
- Rectangle {
- Layout.fillWidth: true
- Layout.alignment: Qt.AlignHCenter
- height: 10
- opacity: 0
- color: "black"
- }
-
- // Ok/Cancel buttons
- RowLayout {
- id: buttons
- spacing: 16
- Layout.topMargin: 16
- Layout.alignment: Qt.AlignRight
-
- MoneroComponents.StandardButton {
- id: cancelButton
- text: qsTr("Cancel") + translationManager.emptyString
- KeyNavigation.tab: passwordInput1
- onClicked: {
- root.close()
- root.rejected()
- }
- }
- MoneroComponents.StandardButton {
- id: okButton
- text: qsTr("Continue") + translationManager.emptyString
- KeyNavigation.tab: cancelButton
- enabled: passwordInput1.text === passwordInput2.text
- onClicked: {
- root.close()
- root.accepted()
- }
- }
- }
- }
- }
-}
diff --git a/components/PassphraseDialog.qml b/components/PassphraseDialog.qml
deleted file mode 100644
index 79dd2f19..00000000
--- a/components/PassphraseDialog.qml
+++ /dev/null
@@ -1,321 +0,0 @@
-// Copyright (c) 2014-2019, 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.7
-import QtQuick.Controls 2.0
-import QtQuick.Dialogs 1.2
-import QtQuick.Layouts 1.1
-import QtQuick.Controls.Styles 1.4
-import QtQuick.Window 2.0
-import FontAwesome 1.0
-
-import "../components" as MoneroComponents
-
-Item {
- id: root
- visible: false
- z: parent.z + 2
-
- property bool isHidden: true
- property alias passphrase: passphaseInput1.text
- property string walletName
- property string errorText
-
- // same signals as Dialog has
- signal accepted()
- signal rejected()
- signal closeCallback()
-
- function open(walletName, errorText) {
- isHidden = true
- passphaseInput1.echoMode = TextInput.Password;
- passphaseInput2.echoMode = TextInput.Password;
-
- inactiveOverlay.visible = true
-
- root.walletName = walletName ? walletName : ""
- root.errorText = errorText ? errorText : "";
-
- leftPanel.enabled = false
- middlePanel.enabled = false
- titleBar.state = "essentials"
-
- root.visible = true;
- passphaseInput1.text = "";
- passphaseInput2.text = "";
- passphaseInput1.focus = true
- }
-
- function close() {
- inactiveOverlay.visible = false
- leftPanel.enabled = true
- middlePanel.enabled = true
- titleBar.state = "default"
- root.visible = false;
- closeCallback();
- }
-
- function toggleIsHidden() {
- passphaseInput1.echoMode = isHidden ? TextInput.Normal : TextInput.Password;
- passphaseInput2.echoMode = isHidden ? TextInput.Normal : TextInput.Password;
- isHidden = !isHidden;
- }
-
- function showError(errorText) {
- open(root.walletName, errorText);
- }
-
- // TODO: implement without hardcoding sizes
- width: 480
- height: 360
-
- ColumnLayout {
- z: inactiveOverlay.z + 1
- id: mainLayout
- spacing: 10
- anchors { fill: parent; margins: 35 }
-
- ColumnLayout {
- id: column
-
- Layout.fillWidth: true
- Layout.alignment: Qt.AlignHCenter
- Layout.maximumWidth: 400
-
- Label {
- text: (root.walletName.length > 0 ? qsTr("Please enter wallet device passphrase for: ") + root.walletName : qsTr("Please enter wallet device passphrase")) + translationManager.emptyString
- Layout.fillWidth: true
-
- font.pixelSize: 16
- font.family: MoneroComponents.Style.fontLight.name
-
- color: MoneroComponents.Style.defaultFontColor
- }
-
- Label {
- text: qsTr("Warning: passphrase entry on host is a security risk as it can be captured by malware. It is advised to prefer device-based passphrase entry.") + translationManager.emptyString
- Layout.fillWidth: true
- wrapMode: Text.Wrap
-
- font.pixelSize: 14
- font.family: MoneroComponents.Style.fontLight.name
-
- color: MoneroComponents.Style.warningColor
- }
-
- Label {
- text: root.errorText
- visible: root.errorText
-
- color: MoneroComponents.Style.errorColor
- font.pixelSize: 16
- font.family: MoneroComponents.Style.fontLight.name
- Layout.fillWidth: true
- wrapMode: Text.Wrap
- }
-
- TextField {
- id : passphaseInput1
- Layout.topMargin: 6
- Layout.fillWidth: true
- horizontalAlignment: TextInput.AlignLeft
- verticalAlignment: TextInput.AlignVCenter
- font.family: MoneroComponents.Style.fontLight.name
- font.pixelSize: 24
- echoMode: TextInput.Password
- bottomPadding: 10
- leftPadding: 10
- topPadding: 10
- color: MoneroComponents.Style.defaultFontColor
- selectionColor: MoneroComponents.Style.textSelectionColor
- selectedTextColor: MoneroComponents.Style.textSelectedColor
- KeyNavigation.tab: passphaseInput2
-
- background: Rectangle {
- radius: 2
- border.color: MoneroComponents.Style.inputBorderColorInActive
- border.width: 1
- color: MoneroComponents.Style.blackTheme ? "black" : "#A9FFFFFF"
-
- MoneroComponents.Label {
- fontSize: 20
- text: isHidden ? FontAwesome.eye : FontAwesome.eyeSlash
- opacity: 0.7
- fontFamily: FontAwesome.fontFamily
- anchors.right: parent.right
- anchors.rightMargin: 15
- anchors.verticalCenter: parent.verticalCenter
- anchors.verticalCenterOffset: 1
-
- MouseArea {
- anchors.fill: parent
- cursorShape: Qt.PointingHandCursor
- hoverEnabled: true
- onClicked: {
- toggleIsHidden()
- }
- onEntered: {
- parent.opacity = 0.9
- parent.fontSize = 24
- }
- onExited: {
- parent.opacity = 0.7
- parent.fontSize = 20
- }
- }
- }
- }
-
- Keys.onEscapePressed: {
- root.close()
- root.rejected()
- }
- }
-
- // padding
- Rectangle {
- Layout.fillWidth: true
- Layout.alignment: Qt.AlignHCenter
- height: 10
- opacity: 0
- color: "transparent"
- }
-
- Label {
- text: qsTr("Please re-enter") + translationManager.emptyString
- Layout.fillWidth: true
-
- font.pixelSize: 16
- font.family: MoneroComponents.Style.fontLight.name
-
- color: MoneroComponents.Style.defaultFontColor
- }
-
- TextField {
- id : passphaseInput2
- Layout.topMargin: 6
- Layout.fillWidth: true
- horizontalAlignment: TextInput.AlignLeft
- verticalAlignment: TextInput.AlignVCenter
- font.family: MoneroComponents.Style.fontLight.name
- font.pixelSize: 24
- echoMode: TextInput.Password
- KeyNavigation.tab: okButton
- bottomPadding: 10
- leftPadding: 10
- topPadding: 10
- color: MoneroComponents.Style.defaultFontColor
- selectionColor: MoneroComponents.Style.dimmedFontColor
- selectedTextColor: MoneroComponents.Style.defaultFontColor
-
- background: Rectangle {
- radius: 2
- border.color: MoneroComponents.Style.inputBorderColorInActive
- border.width: 1
- color: MoneroComponents.Style.blackTheme ? "black" : "#A9FFFFFF"
-
- MoneroComponents.Label {
- fontSize: 20
- text: isHidden ? FontAwesome.eye : FontAwesome.eyeSlash
- opacity: 0.7
- fontFamily: FontAwesome.fontFamily
- anchors.right: parent.right
- anchors.rightMargin: 15
- anchors.verticalCenter: parent.verticalCenter
- anchors.verticalCenterOffset: 1
-
- MouseArea {
- anchors.fill: parent
- cursorShape: Qt.PointingHandCursor
- hoverEnabled: true
- onClicked: {
- toggleIsHidden()
- }
- onEntered: {
- parent.opacity = 0.9
- parent.fontSize = 24
- }
- onExited: {
- parent.opacity = 0.7
- parent.fontSize = 20
- }
- }
- }
- }
-
- Keys.onReturnPressed: {
- if (passphaseInput1.text === passphaseInput2.text) {
- root.close()
- root.accepted()
- }
- }
- Keys.onEscapePressed: {
- root.close()
- root.rejected()
- }
- }
-
- // padding
- Rectangle {
- Layout.fillWidth: true
- Layout.alignment: Qt.AlignHCenter
- height: 10
- opacity: 0
- color: "black"
- }
-
- // Ok/Cancel buttons
- RowLayout {
- id: buttons
- spacing: 16
- Layout.topMargin: 16
- Layout.alignment: Qt.AlignRight
-
- MoneroComponents.StandardButton {
- id: cancelButton
- text: qsTr("Cancel") + translationManager.emptyString
- KeyNavigation.tab: passphaseInput1
- onClicked: {
- root.close()
- root.rejected()
- }
- }
- MoneroComponents.StandardButton {
- id: okButton
- text: qsTr("Continue") + translationManager.emptyString
- KeyNavigation.tab: cancelButton
- enabled: passphaseInput1.text === passphaseInput2.text
- onClicked: {
- root.close()
- root.accepted()
- }
- }
- }
- }
- }
-}
diff --git a/components/PasswordDialog.qml b/components/PasswordDialog.qml
index 4d1c8467..67ffce96 100644
--- a/components/PasswordDialog.qml
+++ b/components/PasswordDialog.qml
@@ -44,34 +44,63 @@ Item {
z: parent.z + 2
property bool isHidden: true
- property alias password: passwordInput.text
+ property alias password: passwordInput1.text
property string walletName
property string errorText
- property bool shiftIsPressed: false
- property bool isCapsLocksActive: false
- property bool backspaceIsPressed: false
+ property bool passwordDialogMode
+ property bool passphraseDialogMode
+ property bool newPasswordDialogMode
// same signals as Dialog has
signal accepted()
+ signal acceptedNewPassword()
+ signal acceptedPassphrase()
signal rejected()
+ signal rejectedNewPassword()
+ signal rejectedPassphrase()
signal closeCallback()
- function open(walletName, errorText) {
+ function _openInit(walletName, errorText) {
isHidden = true
- passwordInput.echoMode = TextInput.Password
- passwordInput.text = ""
- passwordInput.forceActiveFocus();
+ capsLockTextLabel.visible = oshelper.isCapsLock();
+ passwordInput1.echoMode = TextInput.Password
+ passwordInput2.echoMode = TextInput.Password
+ passwordInput1.text = ""
+ passwordInput2.text = ""
+ passwordInput1.forceActiveFocus();
inactiveOverlay.visible = true // draw appwindow inactive
root.walletName = walletName ? walletName : ""
errorTextLabel.text = errorText ? errorText : "";
leftPanel.enabled = false
middlePanel.enabled = false
+ wizard.enabled = false
titleBar.state = "essentials"
root.visible = true;
appWindow.hideBalanceForced = true;
appWindow.updateBalance();
}
+ function open(walletName, errorText) {
+ passwordDialogMode = true;
+ passphraseDialogMode = false;
+ newPasswordDialogMode = false;
+ _openInit(walletName, errorText);
+ }
+
+ function openPassphraseDialog() {
+ passwordDialogMode = false;
+ passphraseDialogMode = true;
+ newPasswordDialogMode = false;
+ _openInit("", "");
+ }
+
+ function openNewPasswordDialog() {
+ passwordDialogMode = false;
+ passphraseDialogMode = false;
+ newPasswordDialogMode = true;
+ _openInit("", "");
+ }
+
function showError(errorText) {
open(root.walletName, errorText);
}
@@ -80,6 +109,7 @@ Item {
inactiveOverlay.visible = false
leftPanel.enabled = true
middlePanel.enabled = true
+ wizard.enabled = true
titleBar.state = "default"
root.visible = false;
@@ -88,6 +118,12 @@ Item {
closeCallback();
}
+ function toggleIsHidden() {
+ passwordInput1.echoMode = isHidden ? TextInput.Normal : TextInput.Password;
+ passwordInput2.echoMode = isHidden ? TextInput.Normal : TextInput.Password;
+ isHidden = !isHidden;
+ }
+
ColumnLayout {
z: inactiveOverlay.z + 1
id: mainLayout
@@ -102,7 +138,11 @@ Item {
Layout.maximumWidth: 400
Label {
- text: (root.walletName.length > 0 ? qsTr("Please enter wallet password for: ") + root.walletName : qsTr("Please enter wallet password")) + translationManager.emptyString
+ text: {
+ var device = passwordDialogMode ? qsTr("wallet password") : qsTr("wallet device passphrase");
+ (root.walletName.length > 0 ? qsTr("Please enter %1 for: ").arg(device) + root.walletName : qsTr("Please enter %1").arg(device)) + translationManager.emptyString;
+ }
+ visible: !newPasswordDialogMode
Layout.fillWidth: true
font.pixelSize: 16
@@ -112,18 +152,40 @@ Item {
}
Label {
+ text: qsTr("Warning: passphrase entry on host is a security risk as it can be captured by malware. It is advised to prefer device-based passphrase entry.") + translationManager.emptyString
+ visible: passphraseDialogMode
+ Layout.fillWidth: true
+ wrapMode: Text.Wrap
+
+ font.pixelSize: 14
+ font.family: MoneroComponents.Style.fontLight.name
+
+ color: MoneroComponents.Style.warningColor
+ }
+
+ Label {
id: errorTextLabel
visible: root.errorText || text !== ""
+ color: MoneroComponents.Style.errorColor
+ font.pixelSize: 16
+ font.family: MoneroComponents.Style.fontLight.name
+ Layout.fillWidth: true
+ wrapMode: Text.Wrap
+ }
+ Label {
+ id: capsLockTextLabel
+ visible: false
color: MoneroComponents.Style.errorColor
font.pixelSize: 16
- font.family: MoneroComponents.Style.fontLight.name
+ font.family: MoneroComponents.Style.fontLight.name
Layout.fillWidth: true
wrapMode: Text.Wrap
+ text: qsTr("CAPSLOCKS IS ON.") + translationManager.emptyString;
}
TextField {
- id : passwordInput
+ id: passwordInput1
Layout.topMargin: 6
Layout.fillWidth: true
horizontalAlignment: TextInput.AlignLeft
@@ -131,24 +193,20 @@ Item {
font.family: MoneroComponents.Style.fontLight.name
font.pixelSize: 24
echoMode: TextInput.Password
- KeyNavigation.tab: okButton
+ KeyNavigation.tab: {
+ if (passwordDialogMode) {
+ return okButton
+ } else {
+ return passwordInput2
+ }
+ }
bottomPadding: 10
leftPadding: 10
topPadding: 10
color: MoneroComponents.Style.defaultFontColor
selectionColor: MoneroComponents.Style.textSelectionColor
selectedTextColor: MoneroComponents.Style.textSelectedColor
-
- onTextChanged: {
- var letter = text[passwordInput.text.length - 1];
- isCapsLocksActive = Utils.isUpperLock(shiftIsPressed, letter);
- if(isCapsLocksActive && !backspaceIsPressed){
- errorTextLabel.text = qsTr("CAPSLOCKS IS ON.") + translationManager.emptyString;
- }
- else{
- errorTextLabel.text = "";
- }
- }
+ onTextChanged: capsLockTextLabel.visible = oshelper.isCapsLock();
background: Rectangle {
radius: 2
@@ -177,8 +235,7 @@ Item {
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
onClicked: {
- passwordInput.echoMode = isHidden ? TextInput.Normal : TextInput.Password;
- isHidden = !isHidden;
+ toggleIsHidden();
}
onEntered: {
parent.opacity = 0.9
@@ -195,30 +252,131 @@ Item {
Keys.enabled: root.visible
Keys.onReturnPressed: {
root.close()
- root.accepted()
+ if (passwordDialogMode) {
+ root.accepted()
+ } else if (newPasswordDialogMode) {
+ root.acceptedNewPassword()
+ } else if (passphraseDialogMode) {
+ root.acceptedPassphrase()
+ }
}
Keys.onEscapePressed: {
root.close()
- root.rejected()
- }
- Keys.onPressed: {
- if(event.key === Qt.Key_Shift){
- shiftIsPressed = true;
+ if (passwordDialogMode) {
+ root.rejected()
+ } else if (newPasswordDialogMode) {
+ root.rejectedNewPassword()
+ } else if (passphraseDialogMode) {
+ root.rejectedPassphrase()
}
- if(event.key === Qt.Key_Backspace){
- backspaceIsPressed = true;
+ }
+ }
+
+ // padding
+ Rectangle {
+ visible: !passwordDialogMode
+ Layout.fillWidth: true
+ Layout.alignment: Qt.AlignHCenter
+ height: 10
+ opacity: 0
+ color: "black"
+ }
+
+ Label {
+ visible: !passwordDialogMode
+ text: qsTr("Please confirm new password") + translationManager.emptyString
+ Layout.fillWidth: true
+
+ font.pixelSize: 16
+ font.family: MoneroComponents.Style.fontLight.name
+
+ color: MoneroComponents.Style.defaultFontColor
+ }
+
+ TextField {
+ id: passwordInput2
+ visible: !passwordDialogMode
+ Layout.topMargin: 6
+ Layout.fillWidth: true
+ horizontalAlignment: TextInput.AlignLeft
+ verticalAlignment: TextInput.AlignVCenter
+ font.family: MoneroComponents.Style.fontLight.name
+ font.pixelSize: 24
+ echoMode: TextInput.Password
+ KeyNavigation.tab: okButton
+ bottomPadding: 10
+ leftPadding: 10
+ topPadding: 10
+ color: MoneroComponents.Style.defaultFontColor
+ selectionColor: MoneroComponents.Style.textSelectionColor
+ selectedTextColor: MoneroComponents.Style.textSelectedColor
+ onTextChanged: capsLockTextLabel.visible = oshelper.isCapsLock();
+
+ background: Rectangle {
+ radius: 2
+ border.color: MoneroComponents.Style.inputBorderColorInActive
+ border.width: 1
+ color: MoneroComponents.Style.blackTheme ? "black" : "#A9FFFFFF"
+
+ MoneroComponents.Label {
+ fontSize: 20
+ text: isHidden ? FontAwesome.eye : FontAwesome.eyeSlash
+ opacity: 0.7
+ fontFamily: FontAwesome.fontFamily
+ anchors.right: parent.right
+ anchors.rightMargin: 15
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.verticalCenterOffset: 1
+
+ MouseArea {
+ anchors.fill: parent
+ cursorShape: Qt.PointingHandCursor
+ hoverEnabled: true
+ onClicked: {
+ toggleIsHidden()
+ }
+ onEntered: {
+ parent.opacity = 0.9
+ parent.fontSize = 24
+ }
+ onExited: {
+ parent.opacity = 0.7
+ parent.fontSize = 20
+ }
+ }
}
}
- Keys.onReleased: {
- if(event.key === Qt.Key_Shift){
- shiftIsPressed = false;
+
+ Keys.onReturnPressed: {
+ if (passwordInput1.text === passwordInput2.text) {
+ root.close()
+ if (newPasswordDialogMode) {
+ root.acceptedNewPassword()
+ } else if (passphraseDialogMode) {
+ root.acceptedPassphrase()
+ }
}
- if(event.key === Qt.Key_Backspace){
- backspaceIsPressed =false;
+ }
+ Keys.onEscapePressed: {
+ root.close()
+ if (newPasswordDialogMode) {
+ root.rejectedNewPassword()
+ } else if (passphraseDialogMode) {
+ root.rejectedPassphrase()
}
}
}
+ // padding
+ Rectangle {
+ visible: !passwordDialogMode
+ Layout.fillWidth: true
+ Layout.alignment: Qt.AlignHCenter
+ height: 10
+ opacity: 0
+ color: "black"
+ }
+
// Ok/Cancel buttons
RowLayout {
id: buttons
@@ -230,10 +388,16 @@ Item {
id: cancelButton
small: true
text: root.walletName.length > 0 ? qsTr("Change wallet") + translationManager.emptyString : qsTr("Cancel") + translationManager.emptyString
- KeyNavigation.tab: passwordInput
+ KeyNavigation.tab: passwordInput1
onClicked: {
root.close()
- root.rejected()
+ if (passwordDialogMode) {
+ root.rejected()
+ } else if (newPasswordDialogMode) {
+ root.rejectedNewPassword()
+ } else if (passphraseDialogMode) {
+ root.rejectedPassphrase()
+ }
}
}
@@ -242,13 +406,19 @@ Item {
small: true
text: qsTr("Continue") + translationManager.emptyString
KeyNavigation.tab: cancelButton
+ enabled: (passwordDialogMode == true) ? true : passwordInput1.text === passwordInput2.text
onClicked: {
root.close()
- root.accepted()
+ if (passwordDialogMode) {
+ root.accepted()
+ } else if (newPasswordDialogMode) {
+ root.acceptedNewPassword()
+ } else if (passphraseDialogMode) {
+ root.acceptedPassphrase()
+ }
}
}
}
-
}
}
}
diff --git a/js/Utils.js b/js/Utils.js
index b709b2ce..4a9a5fed 100644
--- a/js/Utils.js
+++ b/js/Utils.js
@@ -112,25 +112,6 @@ function roundDownToNearestThousand(_num){
return Math.floor(_num/1000.0)*1000
}
-function isAlpha(letter){ return letter.match(/^[A-Za-z0-9]+$/) !== null; }
-
-function isLowerCaseChar(letter){ return letter === letter.toLowerCase(); }
-
-function isUpperLock(shift, letter){
- if(!isAlpha((letter))) return false;
- if(shift) {
- if(isLowerCaseChar(letter))
- return true;
- else
- return false;
- } else {
- if(isLowerCaseChar(letter))
- return false;
- else
- return true;
- }
-}
-
function qmlEach(item, properties, ignoredObjectNames, arr){
// Traverse QML object tree and return components that match
// via property names. Similar to jQuery("myclass").each(...
diff --git a/main.qml b/main.qml
index c6300b52..59a23321 100644
--- a/main.qml
+++ b/main.qml
@@ -573,15 +573,15 @@ ApplicationWindow {
hideProcessingSplash();
console.log(">>> wallet passphrase needed: ")
- passphraseDialog.onAcceptedCallback = function() {
- walletManager.onPassphraseEntered(passphraseDialog.passphrase);
+ passwordDialog.onAcceptedPassphraseCallback = function() {
+ walletManager.onPassphraseEntered(passwordDialog.password);
this.onWalletOpening();
}
- passphraseDialog.onRejectedCallback = function() {
+ passwordDialog.onRejectedPassphraseCallback = function() {
walletManager.onPassphraseEntered("", true);
this.onWalletOpening();
}
- passphraseDialog.open()
+ passwordDialog.openPassphraseDialog()
}
function onWalletUpdate() {
@@ -1498,23 +1498,6 @@ ApplicationWindow {
}
}
- PassphraseDialog {
- id: passphraseDialog
- visible: false
- z: parent.z + 1
- anchors.fill: parent
- property var onAcceptedCallback
- property var onRejectedCallback
- onAccepted: {
- if (onAcceptedCallback)
- onAcceptedCallback();
- }
- onRejected: {
- if (onRejectedCallback)
- onRejectedCallback();
- }
- }
-
PasswordDialog {
id: passwordDialog
visible: false
@@ -1522,6 +1505,8 @@ ApplicationWindow {
anchors.fill: parent
property var onAcceptedCallback
property var onRejectedCallback
+ property var onAcceptedPassphraseCallback
+ property var onRejectedPassphraseCallback
onAccepted: {
if (onAcceptedCallback)
onAcceptedCallback();
@@ -1530,16 +1515,9 @@ ApplicationWindow {
if (onRejectedCallback)
onRejectedCallback();
}
- }
-
- NewPasswordDialog {
- id: newPasswordDialog
- z: parent.z + 1
- visible:false
- anchors.fill: parent
- onAccepted: {
- if (currentWallet.setPassword(newPasswordDialog.password)) {
- appWindow.walletPassword = newPasswordDialog.password;
+ onAcceptedNewPassword: {
+ if (currentWallet.setPassword(passwordDialog.password)) {
+ appWindow.walletPassword = passwordDialog.password;
informationPopup.title = qsTr("Information") + translationManager.emptyString;
informationPopup.text = qsTr("Password changed successfully") + translationManager.emptyString;
informationPopup.icon = StandardIcon.Information;
@@ -1551,7 +1529,14 @@ ApplicationWindow {
informationPopup.onCloseCallback = null;
informationPopup.open();
}
- onRejected: {
+ onRejectedNewPassword: {}
+ onAcceptedPassphrase: {
+ if (onAcceptedPassphraseCallback)
+ onAcceptedPassphraseCallback();
+ }
+ onRejectedPassphrase: {
+ if (onRejectedPassphraseCallback)
+ onRejectedPassphraseCallback();
}
}
diff --git a/monero-wallet-gui.pro b/monero-wallet-gui.pro
index 04648aee..745fa1bd 100644
--- a/monero-wallet-gui.pro
+++ b/monero-wallet-gui.pro
@@ -68,7 +68,8 @@ HEADERS += \
src/qt/mime.h \
src/qt/KeysFiles.h \
src/qt/utils.h \
- src/qt/prices.h
+ src/qt/prices.h \
+ src/qt/macoshelper.h
SOURCES += main.cpp \
filter.cpp \
@@ -334,7 +335,8 @@ linux {
-llmdb \
-lsodium \
-lhidapi-libusb \
- -lcrypto $$TREZOR_LINKER
+ -lcrypto $$TREZOR_LINKER \
+ -lX11
if(!android) {
LIBS+= \
@@ -359,6 +361,8 @@ macx {
# message("using static libraries")
# LIBS+= -Wl,-Bstatic
# }
+ QT += macextras
+ OBJECTIVE_SOURCES += src/qt/macoshelper.mm
LIBS+= \
-L/usr/local/lib \
-L/usr/local/opt/openssl/lib \
@@ -372,6 +376,7 @@ macx {
-lboost_chrono \
-lboost_program_options \
-framework CoreFoundation \
+ -framework AppKit \
-lhidapi \
-lssl \
-lsodium \
diff --git a/oshelper.cpp b/oshelper.cpp
index 36a3c866..d3e4d063 100644
--- a/oshelper.cpp
+++ b/oshelper.cpp
@@ -31,6 +31,20 @@
#include <QDir>
#include <QDebug>
#include <QString>
+#ifdef Q_OS_MAC
+#include "qt/macoshelper.h"
+#endif
+#ifdef Q_OS_WIN32
+#include <windows.h>
+#endif
+#ifdef Q_OS_LINUX
+#include <X11/XKBlib.h>
+#undef KeyPress
+#undef KeyRelease
+#undef FocusIn
+#undef FocusOut
+// #undef those Xlib #defines that conflict with QEvent::Type enum
+#endif
OSHelper::OSHelper(QObject *parent) : QObject(parent)
{
@@ -58,6 +72,27 @@ bool OSHelper::removeTemporaryWallet(const QString &fileName) const
return cache_deleted && address_deleted && keys_deleted;
}
+// https://stackoverflow.com/a/3006934
+bool OSHelper::isCapsLock() const
+{
+ // platform dependent method of determining if CAPS LOCK is on
+#if defined(Q_OS_WIN32) // MS Windows version
+ return GetKeyState(VK_CAPITAL) == 1;
+#elif defined(Q_OS_LINUX) // X11 version
+ Display * d = XOpenDisplay((char*)0);
+ bool caps_state = false;
+ if (d) {
+ unsigned n;
+ XkbGetIndicatorState(d, XkbUseCoreKbd, &n);
+ caps_state = (n & 0x01) == 1;
+ }
+ return caps_state;
+#elif defined(Q_OS_MAC)
+ return MacOSHelper::isCapsLock();
+#endif
+ return false;
+}
+
QString OSHelper::temporaryPath() const
{
return QDir::tempPath();
diff --git a/oshelper.h b/oshelper.h
index 1c11bdde..4d378a9d 100644
--- a/oshelper.h
+++ b/oshelper.h
@@ -42,6 +42,7 @@ public:
Q_INVOKABLE QString temporaryFilename() const;
Q_INVOKABLE QString temporaryPath() const;
Q_INVOKABLE bool removeTemporaryWallet(const QString &walletName) const;
+ Q_INVOKABLE bool isCapsLock() const;
signals:
diff --git a/pages/settings/SettingsWallet.qml b/pages/settings/SettingsWallet.qml
index 1b2c8463..ab80fec2 100644
--- a/pages/settings/SettingsWallet.qml
+++ b/pages/settings/SettingsWallet.qml
@@ -339,7 +339,7 @@ Rectangle {
onClicked: {
passwordDialog.onAcceptedCallback = function() {
if(appWindow.walletPassword === passwordDialog.password){
- newPasswordDialog.open()
+ passwordDialog.openNewPasswordDialog()
} else {
informationPopup.title = qsTr("Error") + translationManager.emptyString;
informationPopup.text = qsTr("Wrong password") + translationManager.emptyString;
diff --git a/qml.qrc b/qml.qrc
index 1200b285..3bced000 100644
--- a/qml.qrc
+++ b/qml.qrc
@@ -96,9 +96,7 @@
<file>pages/SharedRingDB.qml</file>
<file>components/effects/ImageMask.qml</file>
<file>components/IconButton.qml</file>
- <file>components/PassphraseDialog.qml</file>
<file>components/PasswordDialog.qml</file>
- <file>components/NewPasswordDialog.qml</file>
<file>components/InputDialog.qml</file>
<file>components/ProcessingSplash.qml</file>
<file>components/ProgressBar.qml</file>
diff --git a/src/qt/macoshelper.h b/src/qt/macoshelper.h
new file mode 100644
index 00000000..bddf70c6
--- /dev/null
+++ b/src/qt/macoshelper.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2014-2019, 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.
+
+#ifndef MACOSHELPER_H
+#define MACOSHELPER_H
+
+class MacOSHelper
+{
+ MacOSHelper() {}
+
+public:
+ static bool isCapsLock();
+};
+
+#endif //MACOSHELPER_H
diff --git a/src/qt/macoshelper.mm b/src/qt/macoshelper.mm
new file mode 100644
index 00000000..0b29f25f
--- /dev/null
+++ b/src/qt/macoshelper.mm
@@ -0,0 +1,49 @@
+// Copyright (c) 2014-2019, 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.
+
+#include <QtCore>
+#include <QtGui>
+#include <QtMac>
+#include "macoshelper.h"
+
+#import <Foundation/Foundation.h>
+#import <Cocoa/Cocoa.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <ApplicationServices/ApplicationServices.h>
+#include <Availability.h>
+
+bool MacOSHelper::isCapsLock()
+{
+#ifdef __MAC_10_12
+ NSUInteger flags = [NSEvent modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask;
+ return (flags == NSEventModifierFlagCapsLock);
+#else
+ NSUInteger flags = [NSEvent modifierFlags] & NSDeviceIndependentModifierFlagsMask;
+ return (flags & NSAlphaShiftKeyMask);
+#endif
+}
diff --git a/wizard/WizardController.qml b/wizard/WizardController.qml
index f4728ac2..c209faf0 100644
--- a/wizard/WizardController.qml
+++ b/wizard/WizardController.qml
@@ -498,15 +498,15 @@ Rectangle {
splash.close()
console.log(">>> wallet passphrase needed: ");
- passphraseDialog.onAcceptedCallback = function() {
- walletManager.onPassphraseEntered(passphraseDialog.passphrase);
+ passwordDialog.onAcceptedPassphraseCallback = function() {
+ walletManager.onPassphraseEntered(passwordDialog.password);
creatingWalletDeviceSplash();
}
- passphraseDialog.onRejectedCallback = function() {
+ passwordDialog.onRejectedPassphraseCallback = function() {
walletManager.onPassphraseEntered("", true);
creatingWalletDeviceSplash();
}
- passphraseDialog.open()
+ passwordDialog.openPassphraseDialog()
}
function onDeviceButtonRequest(code){