From 88611f30b530f527e4b5276fe9ba2379d631ed60 Mon Sep 17 00:00:00 2001 From: Michael Latouche Date: Mon, 22 Mar 2021 23:07:50 +0100 Subject: [PATCH] 9097 add contextual password helper (#9256) * update back-office forms * Display tip on reset password page as well * add directive for password tip * integrate directove in login screen * forgot the ng-keyup :-) * adapt tooltip directive to potential different Members and Users password settings * remove watcher Co-authored-by: Nathan Woulfe --- .../application/umblogin.directive.js | 6 +- .../application/umbpasswordtip.directive.js | 71 +++++++++++++++++++ .../users/changepassword.directive.js | 9 +++ .../components/application/umb-login.html | 3 +- .../components/users/change-password.html | 4 +- .../changepassword.controller.js | 3 + src/Umbraco.Web.UI/Umbraco/config/lang/en.xml | 2 + .../Umbraco/config/lang/en_us.xml | 2 + src/Umbraco.Web.UI/Umbraco/config/lang/fr.xml | 2 + .../Editors/BackOfficeServerVariables.cs | 6 +- 10 files changed, 104 insertions(+), 4 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/common/directives/components/application/umbpasswordtip.directive.js diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/application/umblogin.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/application/umblogin.directive.js index 36eeb173d69e..ea8b5e81738c 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/application/umblogin.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/application/umblogin.directive.js @@ -16,7 +16,7 @@ function UmbLoginController($scope, $location, currentUserResource, formHelper, mediaHelper, umbRequestHelper, Upload, localizationService, userService, externalLoginInfo, externalLoginInfoService, - resetPasswordCodeInfo, $timeout, authResource, $q, $route) { + resetPasswordCodeInfo, authResource, $q) { const vm = this; @@ -72,6 +72,7 @@ vm.loginSubmit = loginSubmit; vm.requestPasswordResetSubmit = requestPasswordResetSubmit; vm.setPasswordSubmit = setPasswordSubmit; + vm.newPasswordKeyUp = newPasswordKeyUp; vm.labels = {}; localizationService.localizeMany([ vm.usernameIsEmail ? "general_email" : "general_username", @@ -362,6 +363,9 @@ }); } + function newPasswordKeyUp(event) { + vm.passwordVal = event.target.value; + } //// diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/application/umbpasswordtip.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/application/umbpasswordtip.directive.js new file mode 100644 index 000000000000..86e1d3d32f39 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/application/umbpasswordtip.directive.js @@ -0,0 +1,71 @@ +(function () { + 'use strict'; + + angular + .module('umbraco.directives') + .component('umbPasswordTip', { + controller: UmbPasswordTipController, + controllerAs: 'vm', + template: + '{{vm.passwordTip}}', + bindings: { + passwordVal: "<", + minPwdLength: "<", + minPwdNonAlphaNum: "<" + } + }); + + function UmbPasswordTipController(localizationService) { + + let defaultMinPwdLength = Umbraco.Sys.ServerVariables.umbracoSettings.minimumPasswordLength; + let defaultMinPwdNonAlphaNum = Umbraco.Sys.ServerVariables.umbracoSettings.minimumPasswordNonAlphaNum; + + var vm = this; + vm.$onInit = onInit; + vm.$onChanges = onChanges; + + function onInit() { + if (vm.minPwdLength === undefined) { + vm.minPwdLength = defaultMinPwdLength; + } + + if (vm.minPwdNonAlphaNum === undefined) { + vm.minPwdNonAlphaNum = defaultMinPwdNonAlphaNum; + } + + if (vm.minPwdNonAlphaNum > 0) { + localizationService.localize('user_newPasswordFormatNonAlphaTip', [vm.minPwdNonAlphaNum]).then(data => { + vm.passwordNonAlphaTip = data; + updatePasswordTip(0); + }); + } else { + vm.passwordNonAlphaTip = ''; + updatePasswordTip(0); + } + } + + function onChanges(simpleChanges) { + if (simpleChanges.passwordVal) { + if (simpleChanges.passwordVal.currentValue) { + updatePasswordTip(simpleChanges.passwordVal.currentValue.length); + } else { + updatePasswordTip(0); + } + } + } + + const updatePasswordTip = passwordLength => { + const remainingLength = vm.minPwdLength - passwordLength; + if (remainingLength > 0) { + localizationService.localize('user_newPasswordFormatLengthTip', [remainingLength]).then(data => { + vm.passwordTip = data; + if (vm.passwordNonAlphaTip) { + vm.passwordTip += `
${vm.passwordNonAlphaTip}`; + } + }); + } else { + vm.passwordTip = vm.passwordNonAlphaTip; + } + } + } +})(); diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/users/changepassword.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/users/changepassword.directive.js index 8cbdabbf7549..a9961a7579ab 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/users/changepassword.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/users/changepassword.directive.js @@ -11,6 +11,7 @@ vm.cancelChange = cancelChange; vm.showOldPass = showOldPass; vm.showCancelBtn = showCancelBtn; + vm.newPasswordKeyUp = newPasswordKeyUp; var unsubscribe = []; @@ -55,6 +56,11 @@ vm.config.minPasswordLength = 0; } + // Check non-alpha pwd settings for tooltip display + if (vm.config.minNonAlphaNumericChars === undefined) { + vm.config.minNonAlphaNumericChars = 0; + } + //set the model defaults if (!Utilities.isObject(vm.passwordValues)) { //if it's not an object then just create a new one @@ -152,6 +158,9 @@ return vm.config.disableToggle !== true && vm.config.hasPassword; }; + function newPasswordKeyUp(event) { + vm.passwordVal = event.target.value; + } } var component = { diff --git a/src/Umbraco.Web.UI.Client/src/views/components/application/umb-login.html b/src/Umbraco.Web.UI.Client/src/views/components/application/umb-login.html index 1e570b4af6b6..c4b6a4a2ed5d 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/application/umb-login.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/application/umb-login.html @@ -226,7 +226,8 @@

{{greeting}}

- + +
diff --git a/src/Umbraco.Web.UI.Client/src/views/components/users/change-password.html b/src/Umbraco.Web.UI.Client/src/views/components/users/change-password.html index 974f8d6b4ee2..273f56d256ed 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/users/change-password.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/users/change-password.html @@ -43,12 +43,14 @@ required val-server-field="password" ng-minlength="{{vm.config.minPasswordLength}}" - no-dirty-check /> + no-dirty-check + ng-keyup="vm.newPasswordKeyUp($event)"/> Required Minimum {{vm.config.minPasswordLength}} characters {{changePasswordForm.password.errorMsg}} + diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/changepassword/changepassword.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/changepassword/changepassword.controller.js index ab7f5c66e04e..e80aad64f9c9 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/changepassword/changepassword.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/changepassword/changepassword.controller.js @@ -36,6 +36,9 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.ChangePasswordCont if (!$scope.model.config || $scope.model.config.minPasswordLength === undefined) { $scope.model.config.minPasswordLength = 0; } + if (!$scope.model.config || $scope.model.config.minNonAlphaNumericChars === undefined) { + $scope.model.config.minNonAlphaNumericChars = 0; + } //set the model defaults if (!Utilities.isObject($scope.model.value)) { diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml index 2639fbded6e5..9b990ce5d90b 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml @@ -1876,6 +1876,8 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Change your password Change photo New password + Minimum %0% character(s) to go! + There should be at least %0% special character(s) in there. hasn't been locked out The password hasn't been changed Confirm new password diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml index 2435c9db45a0..8394d4e1656a 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml @@ -1895,6 +1895,8 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Change your password Change photo New password + Minimum %0% character(s) to go! + There should be at least %0% special character(s) in there. hasn't been locked out The password hasn't been changed Confirm new password diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/fr.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/fr.xml index d682652782e8..f42ec404b9a8 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/fr.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/fr.xml @@ -1813,6 +1813,8 @@ Pour gérer votre site, ouvrez simplement le backoffice Umbraco et commencez à Changer le mot de passe Changer la photo Nouveau mot de passe + Plus que %0% caractère(s) minimum! + Il devrait y avoir au moins %0% caractère(s) spéciaux. n'a pas été bloqué Le mot de passe n'a pas été modifié Confirmez votre nouveau mot de passe diff --git a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs index 42b5186c03aa..6ec9ac4f90bb 100644 --- a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs +++ b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs @@ -57,7 +57,7 @@ internal Dictionary BareMinimumServerVariables() var keepOnlyKeys = new Dictionary { {"umbracoUrls", new[] {"authenticationApiBaseUrl", "serverVarsJs", "externalLoginsUrl", "currentUserApiBaseUrl", "iconApiBaseUrl"}}, - {"umbracoSettings", new[] {"allowPasswordReset", "imageFileTypes", "maxFileSize", "loginBackgroundImage", "loginLogoImage", "canSendRequiredEmail", "usernameIsEmail"}}, + {"umbracoSettings", new[] {"allowPasswordReset", "imageFileTypes", "maxFileSize", "loginBackgroundImage", "loginLogoImage", "canSendRequiredEmail", "usernameIsEmail", "minimumPasswordLength", "minimumPasswordNonAlphaNum"}}, {"application", new[] {"applicationPath", "cacheBuster"}}, {"isDebuggingEnabled", new string[] { }}, {"features", new [] {"disabledFeatures"}} @@ -100,6 +100,8 @@ internal Dictionary BareMinimumServerVariables() /// internal Dictionary GetServerVariables() { + var userMembershipProvider = Core.Security.MembershipProviderExtensions.GetUsersMembershipProvider(); + var defaultVals = new Dictionary { { @@ -357,6 +359,8 @@ internal Dictionary GetServerVariables() {"showUserInvite", EmailSender.CanSendRequiredEmail}, {"canSendRequiredEmail", EmailSender.CanSendRequiredEmail}, {"showAllowSegmentationForDocumentTypes", false}, + {"minimumPasswordLength", userMembershipProvider.MinRequiredPasswordLength}, + {"minimumPasswordNonAlphaNum", userMembershipProvider.MinRequiredNonAlphanumericCharacters}, } }, {