From d048adf92133b1d01b8501e100c4bd55ba69c5d0 Mon Sep 17 00:00:00 2001 From: Johan Ouwerkerk Date: Sat, 29 Feb 2020 23:49:44 +0100 Subject: [PATCH] UI/UX to ask for the accounts password on start up With this change Keysmith now prompts the user to either: - setup a new password - supply an existing password (if detected) Additionally the organisation/structure of the QML is cleaned up a bit. All QML pages are dedicated QML files and a few signals are introduced to provide slightly better encapsulation/decouple interdependencies. --- src/CMakeLists.txt | 5 +-- src/contents/ui/SetupPassword.qml | 62 ++++++++++++++++++++++++++++++++++++++ src/contents/ui/UnlockAccounts.qml | 56 ++++++++++++++++++++++++++++++++++ src/contents/ui/main.qml | 30 ++++++++++++++++-- src/resources.qrc | 2 ++ 5 files changed, 151 insertions(+), 4 deletions(-) create mode 100644 src/contents/ui/SetupPassword.qml create mode 100644 src/contents/ui/UnlockAccounts.qml diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 01c5acc..fa944cd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -31,11 +31,12 @@ target_link_libraries(keysmith if(ANDROID) kirigami_package_breeze_icons(ICONS - go-next + answer-correct edit-delete edit-undo + go-next list-add - answer-correct + unlock ) endif() diff --git a/src/contents/ui/SetupPassword.qml b/src/contents/ui/SetupPassword.qml new file mode 100644 index 0000000..c08cfb9 --- /dev/null +++ b/src/contents/ui/SetupPassword.qml @@ -0,0 +1,62 @@ +/* + * SPDX-License-Identifier: GPL-3.0-or-later + * SPDX-FileCopyrightText: 2020 Johan Ouwerkerk + */ + +import QtQuick 2.1 +import QtQuick.Layouts 1.2 +import QtQuick.Controls 2.0 as Controls +import org.kde.kirigami 2.8 as Kirigami + +import Keysmith.Application 1.0 +import Keysmith.Models 1.0 as Models + +Kirigami.Page { + id: root + title: i18nc("@title:window", "Password") + + property bool bannerTextError : false + property string bannerText : i18n("Get started by choosing a password to protect your accounts") + property string failedToApplyNewPassword : i18n("Failed to set up your password") + property Models.PasswordRequestModel passwordRequest: Keysmith.passwordRequest() + + ColumnLayout { + anchors { + horizontalCenter: parent.horizontalCenter + } + Controls.Label { + text: bannerText + color: bannerTextError ? Kirigami.Theme.negativeTextColor : Kirigami.Theme.textColor + } + Kirigami.FormLayout { + Kirigami.PasswordField { + id: newPassword + text: "" + Kirigami.FormData.label: i18nc("@label:textbox", "New password:") + inputMethodHints: Qt.ImhNoAutoUppercase | Qt.ImhNoPredictiveText | Qt.ImhSensitiveData | Qt.ImhHiddenText + } + Kirigami.PasswordField { + id: newPasswordCopy + text: "" + Kirigami.FormData.label: i18nc("@label:textbox", "Verify password:") + inputMethodHints: Qt.ImhNoAutoUppercase | Qt.ImhNoPredictiveText | Qt.ImhSensitiveData | Qt.ImhHiddenText + } + } + } + + actions.main : Kirigami.Action { + text: i18n("Apply") + iconName: "answer-correct" + enabled: newPassword.text === newPasswordCopy.text && newPassword.text && newPassword.text.length > 0 + onTriggered: { + // TODO convert to C++ helper, have proper logging? + if (passwordRequest) { + if (!passwordRequest.provideBothPasswords(newPassword.text, newPasswordCopy.text)) { + bannerText = failedToApplyNewPassword; + bannerTextError = true; + } + } + // TODO warn if not + } + } +} diff --git a/src/contents/ui/UnlockAccounts.qml b/src/contents/ui/UnlockAccounts.qml new file mode 100644 index 0000000..0469e54 --- /dev/null +++ b/src/contents/ui/UnlockAccounts.qml @@ -0,0 +1,56 @@ +/* + * SPDX-License-Identifier: GPL-3.0-or-later + * SPDX-FileCopyrightText: 2020 Johan Ouwerkerk + */ + +import QtQuick 2.1 +import QtQuick.Layouts 1.2 +import QtQuick.Controls 2.0 as Controls +import org.kde.kirigami 2.8 as Kirigami + +import Keysmith.Application 1.0 +import Keysmith.Models 1.0 as Models + +Kirigami.Page { + id: root + title: i18nc("@title:window", "Password") + + property bool bannerTextError : false + property string bannerText : i18n("Please provide the password to unlock your accounts") + property string failedToApplyPassword : i18n("Failed to unlock your accounts") + property Models.PasswordRequestModel passwordRequest: Keysmith.passwordRequest() + + ColumnLayout { + anchors { + horizontalCenter: parent.horizontalCenter + } + Controls.Label { + text: bannerText + color: bannerTextError ? Kirigami.Theme.negativeTextColor : Kirigami.Theme.textColor + } + Kirigami.FormLayout { + Kirigami.PasswordField { + id: existingPassword + text: "" + Kirigami.FormData.label: i18nc("@label:textbox", "Password:") + inputMethodHints: Qt.ImhNoAutoUppercase | Qt.ImhNoPredictiveText | Qt.ImhSensitiveData | Qt.ImhHiddenText + } + } + } + + actions.main : Kirigami.Action { + text: i18n("Unlock") + iconName: "unlock" + enabled: existingPassword.text && existingPassword.text.length > 0 + onTriggered: { + // TODO convert to C++ helper, have proper logging? + if (passwordRequest) { + if (!passwordRequest.providePassword(existingPassword.text)) { + bannerText = failedToApplyPassword; + bannerTextError = true; + } + } + // TODO warn if not + } + } +} diff --git a/src/contents/ui/main.qml b/src/contents/ui/main.qml index 61f8eae..9b5c10e 100644 --- a/src/contents/ui/main.qml +++ b/src/contents/ui/main.qml @@ -15,10 +15,23 @@ import org.kde.kirigami 2.4 as Kirigami Kirigami.ApplicationWindow { id: root - pageStack.initialPage: accountsOverviewPage - property bool addActionEnabled: true property Models.AccountListModel accounts: Keysmith.accountListModel() + property Models.PasswordRequestModel passwordRequest: Keysmith.passwordRequest() + + pageStack.initialPage: passwordRequest.previouslyDefined ? unlockAccountsPage : setupPasswordPage + + Component { + id: setupPasswordPage + SetupPassword { + } + } + + Component { + id: unlockAccountsPage + UnlockAccounts { + } + } Component { id: accountsOverviewPage @@ -42,4 +55,17 @@ Kirigami.ApplicationWindow { } } } + + // TODO maybe have a onPasswordProvided handler to push a "progress" page to provide visual feedback for devices where key derivation is slow? + Connections { + target: passwordRequest + onDerivedKey : { + // TODO convert to C++ helper, have proper logging? + if (passwordRequest.keyAvailable) { + pageStack.pop(); + pageStack.push(accountsOverviewPage); + } + // TODO warn if not + } + } } diff --git a/src/resources.qrc b/src/resources.qrc index 8b4621f..dd1446e 100644 --- a/src/resources.qrc +++ b/src/resources.qrc @@ -10,5 +10,7 @@ contents/ui/AccountEntryView.qml contents/ui/AccountsOverview.qml contents/ui/AddAccount.qml + contents/ui/UnlockAccounts.qml + contents/ui/SetupPassword.qml