fix(PasswordView): Password instructions missing max length requirement

- set the pass max length to 100 (via `Constants`, not with a hardcoded
regexp)
- delay the validation until the user hits the limit
- clear the categories (lower/upper/num/sym) info if the password is
cleared too
- update the error messages according to latest Figma designs

Fixes #16239
This commit is contained in:
Lukáš Tinkl 2024-10-15 12:45:50 +02:00 committed by Lukáš Tinkl
parent 62f85acf31
commit b052416666
5 changed files with 29 additions and 21 deletions

View File

@ -53,6 +53,7 @@ SplitView {
Switch { Switch {
id: createNewPassword id: createNewPassword
text: "Create new password" text: "Create new password"
checked: true
} }
Switch { Switch {
@ -63,9 +64,12 @@ SplitView {
Switch { Switch {
id: titleVisibleSwitch id: titleVisibleSwitch
text: "Title visible" text: "Title visible"
checked: true
} }
} }
} }
} }
// category: Views // category: Views
// https://www.figma.com/design/17fc13UBFvInrLgNUKJJg5/Kuba%E2%8E%9CDesktop?node-id=41014-22302&node-type=frame&t=0JUvGJPEhU9e9QB9-0

View File

@ -1,5 +1,5 @@
import QtQuick 2.14 import QtQuick 2.15
import QtQuick.Controls 2.14 import QtQuick.Controls 2.15
import StatusQ.Core.Theme 0.1 import StatusQ.Core.Theme 0.1
import StatusQ.Core 0.1 import StatusQ.Core 0.1
@ -42,7 +42,7 @@ StatusProgressBar {
id: control id: control
/*! /*!
\qmlproperty string StatusPasswordStrengthIndicator::strength \qmlproperty int StatusPasswordStrengthIndicator::strength
This property holds the password strength value. Possible values are: This property holds the password strength value. Possible values are:
\list \list
\li StatusPasswordStrengthIndicator.Strength.None \li StatusPasswordStrengthIndicator.Strength.None
@ -53,7 +53,7 @@ StatusProgressBar {
\li StatusPasswordStrengthIndicator.Strength.Great \li StatusPasswordStrengthIndicator.Strength.Great
\endlist \endlist
*/ */
property var strength property int strength
/*! /*!
\qmlproperty string StatusPasswordStrengthIndicator::labelVeryWeak \qmlproperty string StatusPasswordStrengthIndicator::labelVeryWeak
This property holds the text shown when the strength is StatusPasswordStrengthIndicator.Strength.VeryWeak. This property holds the text shown when the strength is StatusPasswordStrengthIndicator.Strength.VeryWeak.

View File

@ -74,7 +74,8 @@ ColumnLayout {
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
placeholderText: qsTr("Confirm your password (again)") placeholderText: qsTr("Confirm your password (again)")
echoMode: showPassword ? TextInput.Normal : TextInput.Password echoMode: showPassword ? TextInput.Normal : TextInput.Password
validator: RegExpValidator { regExp: /^[!-~]{0,64}$/ } // That incudes NOT extended ASCII printable characters less space and a maximum of 64 characters allowed validator: RegExpValidator { regExp: /^[!-~]+$/ } // That includes NOT extended ASCII printable characters less space
maximumLength: Constants.maxPasswordLength // a maximum of 100 characters allowed
rightPadding: showHideCurrentIcon.width + showHideCurrentIcon.anchors.rightMargin + Style.current.padding / 2 rightPadding: showHideCurrentIcon.width + showHideCurrentIcon.anchors.rightMargin + Style.current.padding / 2
onTextChanged: { onTextChanged: {
errorTxt.text = "" errorTxt.text = ""

View File

@ -1,10 +1,7 @@
import QtQuick 2.14 import QtQuick 2.15
import QtQuick.Controls 2.14 import QtQuick.Controls 2.15
import QtQuick.Layouts 1.12 import QtQuick.Layouts 1.15
import shared.panels 1.0
import shared.controls 1.0
import shared.stores 1.0
import utils 1.0 import utils 1.0
import StatusQ.Controls 0.1 import StatusQ.Controls 0.1
@ -16,7 +13,8 @@ import StatusQ.Popups 0.1
ColumnLayout { ColumnLayout {
id: root id: root
property bool ready: newPswInput.text.length >= Constants.minPasswordLength && newPswInput.text === confirmPswInput.text && errorTxt.text === "" readonly property bool ready: newPswInput.text.length >= Constants.minPasswordLength && newPswInput.text === confirmPswInput.text && errorTxt.text === ""
property bool createNewPsw: true property bool createNewPsw: true
property string title: createNewPsw ? qsTr("Create a password") : qsTr("Change your password") property string title: createNewPsw ? qsTr("Create a password") : qsTr("Change your password")
property bool titleVisible: true property bool titleVisible: true
@ -86,14 +84,15 @@ ColumnLayout {
property bool containsNumbers: false property bool containsNumbers: false
property bool containsSymbols: false property bool containsSymbols: false
readonly property var validatorRegexp: /^[!-~]{0,64}$/ readonly property var validatorRegexp: /^[!-~]+$/
readonly property string validatorErrMessage: qsTr("Only letters, numbers, underscores and hyphens allowed") readonly property string validatorErrMessage: qsTr("Only ASCII letters, numbers, and symbols are allowed")
readonly property string passTooLongErrMessage: qsTr("Maximum %n character(s)", "", Constants.maxPasswordLength)
// Password strength categorization / validation // Password strength categorization / validation
function lowerCaseValidator(text) { return (/[a-z]/.test(text)) } function lowerCaseValidator(text) { return (/[a-z]/.test(text)) }
function upperCaseValidator(text) { return (/[A-Z]/.test(text)) } function upperCaseValidator(text) { return (/[A-Z]/.test(text)) }
function numbersValidator(text) { return (/\d/.test(text)) } function numbersValidator(text) { return (/\d/.test(text)) }
// That incudes NOT extended ASCII printable symbols less space: // That includes NOT extended ASCII printable symbols less space:
function symbolsValidator(text) { return (/[!-\/:-@[-`{-~]/.test(text)) } function symbolsValidator(text) { return (/[!-\/:-@[-`{-~]/.test(text)) }
function validateCharacterSet(text) { function validateCharacterSet(text) {
@ -101,6 +100,10 @@ ColumnLayout {
errorTxt.text = d.validatorErrMessage errorTxt.text = d.validatorErrMessage
return false return false
} }
if(text.length > Constants.maxPasswordLength) {
errorTxt.text = d.passTooLongErrMessage
return false
}
return true return true
} }
@ -125,15 +128,15 @@ ColumnLayout {
// 3 rules to validate: // 3 rules to validate:
// * Password is in pwnd passwords database // * Password is in pwnd passwords database
if(isInPwndDatabase()) if(isInPwndDatabase())
errorTxt.text = qsTr("This password has been pwned and shouldn't be used") errorTxt.text = qsTr("Password pwned, shouldn't be used")
// * Common password // * Common password
else if(isCommonPassword()) else if(isCommonPassword())
errorTxt.text = qsTr("This password is a common word and shouldn't be used") errorTxt.text = qsTr("Common password, shouldn't be used")
// * Password too short // * Password too short
else if(isTooShort()) else if(isTooShort())
errorTxt.text = qsTr("Password must be at least %n character(s) long", "", Constants.minPasswordLength) errorTxt.text = qsTr("Minimum %n character(s)", "", Constants.minPasswordLength)
} }
function isInPwndDatabase() { function isInPwndDatabase() {
@ -262,13 +265,13 @@ ColumnLayout {
// Update strength indicator: // Update strength indicator:
strengthInditactor.strength = d.convertStrength(root.passwordStrengthScoreFunction(newPswInput.text)) strengthInditactor.strength = d.convertStrength(root.passwordStrengthScoreFunction(newPswInput.text))
if(!d.validateCharacterSet(text)) return
d.containsLower = d.lowerCaseValidator(text) d.containsLower = d.lowerCaseValidator(text)
d.containsUpper = d.upperCaseValidator(text) d.containsUpper = d.upperCaseValidator(text)
d.containsNumbers = d.numbersValidator(text) d.containsNumbers = d.numbersValidator(text)
d.containsSymbols = d.symbolsValidator(text) d.containsSymbols = d.symbolsValidator(text)
if(!d.validateCharacterSet(text)) return
if (text.length === confirmPswInput.text.length) { if (text.length === confirmPswInput.text.length) {
root.checkPasswordMatches(false) root.checkPasswordMatches(false)
} }
@ -306,7 +309,6 @@ ColumnLayout {
Rectangle { Rectangle {
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true
Layout.minimumHeight: 80 Layout.minimumHeight: 80
border.color: Theme.palette.baseColor2 border.color: Theme.palette.baseColor2
border.width: 1 border.width: 1

View File

@ -1046,6 +1046,7 @@ QtObject {
readonly property string wrongDerivationPathError: "error parsing derivation path" readonly property string wrongDerivationPathError: "error parsing derivation path"
readonly property int minPasswordLength: 10 readonly property int minPasswordLength: 10
readonly property int maxPasswordLength: 100
readonly property QtObject suggestedRoutesExtraParamsProperties: QtObject { readonly property QtObject suggestedRoutesExtraParamsProperties: QtObject {
readonly property string packId: "packID" readonly property string packId: "packID"