Index: sources/gui/qml/pages/UserConfirmation.qml =================================================================== diff -u -r09a43d162e61ae02c73364e050d90957d736f322 -r4696b5fa37cc2ee744582fc70228736cad55ca63 --- sources/gui/qml/pages/UserConfirmation.qml (.../UserConfirmation.qml) (revision 09a43d162e61ae02c73364e050d90957d736f322) +++ sources/gui/qml/pages/UserConfirmation.qml (.../UserConfirmation.qml) (revision 4696b5fa37cc2ee744582fc70228736cad55ca63) @@ -32,11 +32,11 @@ property bool isPassword : false property bool showPasswordReEntryField : false readonly property string password : _password.textInput.text - readonly property string passwordReEntry : _passwordReEntryField.textInput.text + readonly property string passwordReEntry : _passwordReEntry.textInput.text property alias message : _message.text function clearPasswordReEntry() { - _passwordReEntryField.textInput.text = "" + _passwordReEntry.textInput.text = "" } function clearPassword() { @@ -52,12 +52,11 @@ top : parent.top topMargin : { if(_root.showPasswordReEntryField) { - return topMarginContent + 120 - _passwordReEntryField.height + return topMarginContent + 120 - _passwordReEntry.height } else { return topMarginContent + 120 // moved a little down to be more on center and close to keyboard top edge. } } - horizontalCenter: parent.horizontalCenter } textInput.inputMethodHints : Qt.ImhNone @@ -81,7 +80,7 @@ onReleased : _password.textInput.echoMode = TextInput.Password } - TextEntry { id : _passwordReEntryField + TextEntry { id : _passwordReEntry clip : true visible : _root.showPasswordReEntryField textInput .width : 450 @@ -95,10 +94,10 @@ } Image { id : _showPasswordReEntryImage - visible : _passwordReEntryField.visible - anchors.left : _passwordReEntryField.right + visible : _passwordReEntry.visible + anchors.left : _passwordReEntry.right anchors.leftMargin : Variables.minVGap - anchors.verticalCenter : _passwordReEntryField.verticalCenter + anchors.verticalCenter : _passwordReEntry.verticalCenter width : Variables.iconsDiameter height : Variables.iconsDiameter source : "qrc:/images/iEye" @@ -107,8 +106,8 @@ MouseArea { anchors.fill: _showPasswordReEntryImage anchors.margins: -20 - onPressed : _passwordReEntryField.textInput.echoMode = TextInput.Normal - onReleased : _passwordReEntryField.textInput.echoMode = TextInput.Password + onPressed : _passwordReEntry.textInput.echoMode = TextInput.Normal + onReleased : _passwordReEntry.textInput.echoMode = TextInput.Password } Text { id : _message Index: sources/gui/qml/pages/settings/SettingsStack.qml =================================================================== diff -u -r09a43d162e61ae02c73364e050d90957d736f322 -r4696b5fa37cc2ee744582fc70228736cad55ca63 --- sources/gui/qml/pages/settings/SettingsStack.qml (.../SettingsStack.qml) (revision 09a43d162e61ae02c73364e050d90957d736f322) +++ sources/gui/qml/pages/settings/SettingsStack.qml (.../SettingsStack.qml) (revision 4696b5fa37cc2ee744582fc70228736cad55ca63) @@ -237,19 +237,13 @@ } UserConfirmation { id: _servicePassword - property bool isDefaultPasswordSet : (vSettings.servicePass != "") - + property bool isPassword_Accepted : false + property bool isDefaultPasswordSet : (vSettings.servicePass != "") + onIsDefaultPasswordSetChanged: console.log(vSettings.servicePass) itemIndex : SettingsStack.Services - title : qsTr("Service Password") + title : isDefaultPasswordSet ? qsTr("Service Password") : qsTr("Set Service Password") isPassword: true showPasswordReEntryField: !isDefaultPasswordSet - onVisibleChanged: { - if (visible) { - if (!isDefaultPasswordSet) { - _servicePassword.title = qsTr("Default Service Password") - } - } - } onBackClicked : { clearPassword() if(!isDefaultPasswordSet){ @@ -258,42 +252,36 @@ _settingsHome.notificationText = "" } onConfirmClicked: { + isPassword_Accepted = false + let password = _servicePassword.password if ( !isDefaultPasswordSet ) { - let password = _servicePassword.password let passwordReEntry = _servicePassword.passwordReEntry - if (password == passwordReEntry) { - if(vSettings.isPasswordConforming(password)) { - vSettings.servicePass = vSettings.encryptString(password) - } else { - _servicePassword.title = qsTr("Malformed Password Entry") - } - } else { - _servicePassword.title = qsTr("Mismatched Password Entry") - } - clearPassword() + if ( password != passwordReEntry ) { _servicePassword.notificationText = qsTr("Mismatched Password Entry"); return } + if (!vSettings.isPasswordValid(password)) { _servicePassword.notificationText = qsTr("Malformed Password Entry" ); return } + + vSettings.updatePassword(password) + _servicePassword.isPassword_Accepted = true + _servicePassword.notificationText = "" clearPasswordReEntry() } else { - if ( vSettings.encryptString(password) === vSettings.servicePass ) { - _settingsHome.notificationText = "" - vAdjustmentServiceMode.doAdjustment() - if ( vSettings.noCANBus ) { // if NoCANBus is set don't wait for HD and go to service mode. - gotoServiceMode(true) - } - clearPassword() - clearPasswordReEntry() - pop() + if (!vSettings.isPasswordMatch(password)) { _servicePassword.notificationText = qsTr("Incorrect service password"); return } + + _servicePassword.isPassword_Accepted = true + _servicePassword.notificationText = "" + vAdjustmentServiceMode.doAdjustment() + if ( vSettings.noCANBus ) { // if NoCANBus is set don't wait for HD and go to service mode. + gotoServiceMode(true) } - else { - _settingsHome.notificationText = qsTr("Incorrect service password") - } } + clearPassword() + pop() // pop back to settings screen and wait for the HD-OpMode change to Service_Mode to update the settings screen. } } Connections { target: vAdjustmentServiceMode function onAdjustmentTriggered ( vValue ) { - if ( vAdjustmentServiceMode.adjustment_Accepted ) { - _settingsHome.notificationText = "" + if ( vAdjustmentServiceMode.adjustment_Accepted ) { + _settingsHome.notificationText = "" } else { _settingsHome.notificationText = vAdjustmentServiceMode.text() @@ -302,7 +290,7 @@ } function gotoServiceMode( vservice ) { -// push( _settingsHome , vservice ) + if ( ! _servicePassword.isPassword_Accepted ) return serviceMode = vservice if ( vservice ) _mainMenu.hidden = true Index: sources/view/settings/VSettings.cpp =================================================================== diff -u -r09a43d162e61ae02c73364e050d90957d736f322 -r4696b5fa37cc2ee744582fc70228736cad55ca63 --- sources/view/settings/VSettings.cpp (.../VSettings.cpp) (revision 09a43d162e61ae02c73364e050d90957d736f322) +++ sources/view/settings/VSettings.cpp (.../VSettings.cpp) (revision 4696b5fa37cc2ee744582fc70228736cad55ca63) @@ -38,7 +38,10 @@ void VSettings::servicePass_post(const QString &vservicePass) { Storage::Settings settings; - settings.save(servicePassCategory(), servicePassGroup(), servicePassKey(), vservicePass); + if ( settings.save(servicePassCategory(), servicePassGroup(), servicePassKey(), vservicePass) != 0 ) { + servicePass(""); + // FIXME: Notify UI with a message + } } void VSettings::alarmVolume_post(const quint8 &valarmVolume) { @@ -210,32 +213,65 @@ } /*! - * \brief VSettings::isPasswordConforming - * \details Validates the passed string for conforming to the "at least one - * capital letter, at least one digit, at least one symbol" rule + * \brief VSettings::isPasswordValid + * \details Validates the passed string for conforming to the + * - at least one capital letter, + * - at least one digit, + * - at least one symbol + * rule * \param vPassword - the string to check * \returns true if string pass conforms, false otherwise */ -bool VSettings::isPasswordConforming(const QString vPassword) { - QRegularExpression passwordStringRegexObject; +bool View::VSettings::isPasswordValid(const QString &vPassword) { + int minLen = 8 ; + QString pla = "(?=.*[%1])" ; // positive look ahead + QString regSntnc = "^%1$" ; // regular expression sentence with has a start/end + QString regUpper = "A-Z" ; + QString regLower = "a-z" ; + QString regDigit = "0-9" ; + QString regSymbl = "@$!%*?&.,_-" ; + QString rln = "[%1]{%2,}" ; - // Check for at least one capitalized letter - passwordStringRegexObject.setPattern("[A-Z]{1,}"); - bool hasCapitalized = passwordStringRegexObject.match(vPassword).hasMatch(); + // "^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[@$!%*?&])[A-Za-z0-9@$!%*?&]{8,}$" + QString regStr = regSntnc.arg( + pla.arg(regUpper) + + pla.arg(regLower) + + pla.arg(regDigit) + + pla.arg(regSymbl) + + rln.arg(regUpper + + regLower + + regDigit + + regSymbl) + .arg(minLen ) + ); + QRegularExpression passwordRegex(regStr); + bool ok; + ok = passwordRegex.match(vPassword).hasMatch(); + return ok; +} - // Check for at least one digit - passwordStringRegexObject.setPattern("[0-9]{1,}"); - bool hasNumeric = passwordStringRegexObject.match(vPassword).hasMatch(); +#include - // Check for at least one special character, defining it as a non-alphanumeric character - passwordStringRegexObject.setPattern("[^A-Za-z0-9]{1,}"); - bool hasSymbol = passwordStringRegexObject.match(vPassword).hasMatch(); - - return hasCapitalized && hasNumeric && hasSymbol; +QString VSettings::encryptString(const QString &vString) { + // FIXME: Move this to the utility, storage or settings controller class for more general use. + QString salt = "DVT-HD0004"; // FIXME: Use the actual HD serial number + int iter = 1000; + int len = 16; + auto shuffle = [](const QString &vString) { + // FIXME: Implement this, and make this a function and move this to the utility or storage class for more general use. + QString shuffled = vString; + return shuffled.toUtf8().toHex(); + }; + QCryptographicHash::Algorithm algorithm = QCryptographicHash::Sha512; + QByteArray hashed = QPasswordDigestor::deriveKeyPbkdf2(algorithm, vString.toUtf8(), shuffle(salt), iter, len); + return hashed.toHex(); } -// TODO this is a mock, need to add real encrypted string -QString VSettings::encryptString(const QString vString) { - return vString; +bool View::VSettings::isPasswordMatch(const QString &vPassword) { + return _servicePass == encryptString(vPassword); } +void View::VSettings::updatePassword(const QString &vPassword) +{ + servicePass(encryptString(vPassword)); +} Index: sources/view/settings/VSettings.h =================================================================== diff -u -r09a43d162e61ae02c73364e050d90957d736f322 -r4696b5fa37cc2ee744582fc70228736cad55ca63 --- sources/view/settings/VSettings.h (.../VSettings.h) (revision 09a43d162e61ae02c73364e050d90957d736f322) +++ sources/view/settings/VSettings.h (.../VSettings.h) (revision 4696b5fa37cc2ee744582fc70228736cad55ca63) @@ -63,9 +63,9 @@ PROPERTY(QStringList , categorys , {} ) PROPERTY(QVariantMap , instructions , {} ) - SETTINGS(QString , servicePass , QString() , Storage::Settings_Category_SettingsSystem , "Service" , "Password" ) - SETTINGS(quint8 , alarmVolume , 100 , Storage::Settings_Category_SettingsSystem , "Alarm" , "Volume" ) - SETTINGS(bool , noCANBus , false , Storage::Settings_Category_NoCANBus , "Navigation" , "Create Treatment To Patient ID" ) + SETTINGS(QString , servicePass , "" , Storage::Settings_Category_SettingsSystem , "Service" , "Password" ) + SETTINGS(quint8 , alarmVolume , 100 , Storage::Settings_Category_SettingsSystem , "Alarm" , "Volume" ) + SETTINGS(bool , noCANBus , false , Storage::Settings_Category_NoCANBus , "Navigation" , "Create Treatment To Patient ID" ) VIEW_DEC(VSettings, SettingsData) @@ -74,9 +74,12 @@ void updateInstructions ( const QString &vGroup, const TKeysList &vKeysList, const QVariantList &vValues ); void updateInstructions ( const QString &vGroup ); + QString encryptString (const QString &vString ); + public slots: - bool isPasswordConforming(const QString vPassword); - QString encryptString (const QString vString ); + bool isPasswordValid (const QString &vPassword); + bool isPasswordMatch (const QString &vPassword); + void updatePassword (const QString &vPassword); private slots: void onActionReceive (GuiActionType vAction, const QVariantList &vData);