diff --git a/src/app/components/mno-password-strength/mno-password-strength.coffee b/src/app/components/mno-password-strength/mno-password-strength.coffee new file mode 100644 index 00000000..205d0755 --- /dev/null +++ b/src/app/components/mno-password-strength/mno-password-strength.coffee @@ -0,0 +1,149 @@ +angular.module 'mnoEnterpriseAngular' + .directive 'mnoPasswordStrength', (MnoErrorsHandler) -> + require: "ngModel" + restrict: 'A' + scope: + passwordScore: '=' #outject score + + link: (scope, element, attrs, ctrl) -> + measureStrength = (p) -> + matches = + pos: {} + neg: {} + + counts = + pos: {} + neg: + seqLetter: 0 + seqNumber: 0 + seqSymbol: 0 + + tmp = undefined + strength = 0 + letters = "abcdefghijklmnopqrstuvwxyz" + numbers = "01234567890" + symbols = "\\!@#$%&/()=?¿" + back = undefined + forth = undefined + + if p + # Benefits + matches.pos.lower = p.match(/[a-z]/g) + matches.pos.upper = p.match(/[A-Z]/g) + matches.pos.numbers = p.match(/\d/g) + matches.pos.symbols = p.match(/[$-/:-?{-~!^_`\[\]]/g) + matches.pos.middleNumber = p.slice(1, -1).match(/\d/g) + matches.pos.middleSymbol = p.slice(1, -1).match(/[$-/:-?{-~!^_`\[\]]/g) + counts.pos.lower = (if matches.pos.lower then matches.pos.lower.length else 0) + counts.pos.upper = (if matches.pos.upper then matches.pos.upper.length else 0) + counts.pos.numbers = (if matches.pos.numbers then matches.pos.numbers.length else 0) + counts.pos.symbols = (if matches.pos.symbols then matches.pos.symbols.length else 0) + tmp = _.reduce(counts.pos, (memo, val) -> + # if has count will add 1 + memo + Math.min(1, val) + , 0) + counts.pos.numChars = p.length + tmp += (if (counts.pos.numChars >= 8) then 1 else 0) + counts.pos.requirements = (if (tmp >= 3) then tmp else 0) + counts.pos.middleNumber = (if matches.pos.middleNumber then matches.pos.middleNumber.length else 0) + counts.pos.middleSymbol = (if matches.pos.middleSymbol then matches.pos.middleSymbol.length else 0) + + # Deductions + matches.neg.consecLower = p.match(/(?=([a-z]{2}))/g) + matches.neg.consecUpper = p.match(/(?=([A-Z]{2}))/g) + matches.neg.consecNumbers = p.match(/(?=(\d{2}))/g) + matches.neg.onlyNumbers = p.match(/^[0-9]*$/g) + matches.neg.onlyLetters = p.match(/^([a-z]|[A-Z])*$/g) + counts.neg.consecLower = (if matches.neg.consecLower then matches.neg.consecLower.length else 0) + counts.neg.consecUpper = (if matches.neg.consecUpper then matches.neg.consecUpper.length else 0) + counts.neg.consecNumbers = (if matches.neg.consecNumbers then matches.neg.consecNumbers.length else 0) + + # sequential letters (back and forth) + i = 0 + while i < letters.length - 2 + p2 = p.toLowerCase() + forth = letters.substring(i, parseInt(i + 3)) + back = _(forth).split("").reverse() + counts.neg.seqLetter++ if p2.indexOf(forth) isnt -1 or p2.indexOf(back) isnt -1 + i++ + + # sequential numbers (back and forth) + i = 0 + while i < numbers.length - 2 + forth = numbers.substring(i, parseInt(i + 3)) + back = _(forth).split("").reverse() + counts.neg.seqNumber++ if p.indexOf(forth) isnt -1 or p.toLowerCase().indexOf(back) isnt -1 + i++ + + # sequential symbols (back and forth) + i = 0 + while i < symbols.length - 2 + forth = symbols.substring(i, parseInt(i + 3)) + back = _(forth).split("").reverse() + counts.neg.seqSymbol++ if p.indexOf(forth) isnt -1 or p.toLowerCase().indexOf(back) isnt -1 + i++ + + # repeated chars + counts.neg.repeated = _.chain(p.toLowerCase().split("")).countBy((val) -> + val + ).reject((val) -> + val is 1 + ).reduce((memo, val) -> + memo + val + , 0).value() + + # Calculations + strength += counts.pos.numChars * 4 + strength += (counts.pos.numChars - counts.pos.upper) * 2 if counts.pos.upper + strength += (counts.pos.numChars - counts.pos.lower) * 2 if counts.pos.lower + strength += counts.pos.numbers * 4 if counts.pos.upper or counts.pos.lower + strength += counts.pos.symbols * 6 + strength += (counts.pos.middleSymbol + counts.pos.middleNumber) * 2 + strength += counts.pos.requirements * 2 + strength -= counts.neg.consecLower * 2 + strength -= counts.neg.consecUpper * 2 + strength -= counts.neg.consecNumbers * 2 + strength -= counts.neg.seqNumber * 3 + strength -= counts.neg.seqLetter * 3 + strength -= counts.neg.seqSymbol * 3 + strength -= counts.pos.numChars if matches.neg.onlyNumbers + strength -= counts.pos.numChars if matches.neg.onlyLetters + strength -= (counts.neg.repeated / counts.pos.numChars) * 10 if counts.neg.repeated + Math.max 0, Math.min(100, Math.round(strength)) + + getPwStrength = (s) -> + switch Math.round(s / 20) + when 0, 1 + "weak" + when 2,3 + "good" + when 4,5 + "secure" + + getClass = (s) -> + switch getPwStrength(s) + when 'weak' + "danger" + when 'good' + "warning" + when 'secure' + "success" + + isPwStrong = (s) -> + switch getPwStrength(s) + when 'weak' + false + else + true + + scope.$watch (-> ctrl.$modelValue), -> + scope.value = measureStrength(ctrl.$modelValue) + scope.pwStrength = getPwStrength(scope.value) + ctrl.$setValidity('password-strength', isPwStrong(scope.value)) + if scope.passwordScore? + scope.passwordScore.value = scope.pwStrength + scope.passwordScore.class = getClass(scope.value) + scope.passwordScore.showTip = (ctrl.$modelValue? && ctrl.$modelValue != '' && !isPwStrong(scope.value)) + + + return diff --git a/src/app/views/auth/password/reset.coffee b/src/app/views/auth/password/reset.coffee new file mode 100644 index 00000000..44931287 --- /dev/null +++ b/src/app/views/auth/password/reset.coffee @@ -0,0 +1,37 @@ +angular.module('mnoEnterpriseAngular') + .controller 'PasswordResetCtrl', ($state, $location, Auth, toastr, MnoErrorsHandler) -> + 'ngInject' + + vm = this + vm.resetConfirmed = false + vm.user = { + $pwdScore: {} + } + + vm.password_reset = -> + if vm.form.$invalid && !MnoErrorsHandler.onlyServerError(vm.form) + return + else if vm.user.password != vm.user.password_confirmation + return + + MnoErrorsHandler.resetErrors(vm.form) + + vm.user.reset_password_token = $location.search().reset_password_token + Auth.resetPassword(vm.user).then( + -> + toastr.info('devise.passwords.updated', { + timeOut: 0, + closeButton: true, + extendedTimeOut: 0 + }) + Auth.login(vm.user).then( + -> + $state.go('home.impac') + ).finally( -> vm.resetConfirmed = true) + (error) -> + MnoErrorsHandler.processServerError(error, vm.form) + ).finally( -> vm.hasClicked = false) + + return true + + return diff --git a/src/app/views/auth/password/reset.html b/src/app/views/auth/password/reset.html new file mode 100644 index 00000000..47adedd5 --- /dev/null +++ b/src/app/views/auth/password/reset.html @@ -0,0 +1,57 @@ +
+
+
+ +
+
+
-->