From 24e615da1e2776af9d42d070e2aaac254b30a666 Mon Sep 17 00:00:00 2001 From: Aysel Afsar Date: Thu, 11 Feb 2016 08:48:11 -0500 Subject: [PATCH] LT-97: - Remove zxcvbn package because of version conflict, - Add passwordOptions in ActiveEntry.configure - Toggle showPasswordStrengthIndicator to show password strength meter ui, toggle requireRegexValidation to set password regex for validation or requireStrongPasswords to create strong passwords by using zxcvbn. - Sign in/ sing up when enter key is pressed --- LesionTracker/.meteor/versions | 3 +- LesionTracker/activeEntry.js | 5 +- Packages/active-entry/Contributing.md | 5 + Packages/active-entry/circle.yml | 47 +- .../changePassword/changePassword.html | 40 + .../changePassword/changePassword.js | 84 + .../changePassword/changePassword.less | 5 + .../components/entrySignIn/entrySignIn.js | 5 +- .../components/entrySignUp/entrySignUp.js | 11 +- Packages/active-entry/lib/ActiveEntry.js | 18 +- .../active-entry/lib/checkPasswordStrength.js | 69 +- .../lib/jquery.pwstrength.bootstrap.js | 1351 +++++++++-------- Packages/active-entry/package.js | 12 +- .../tests/gagarin/activeEntryTests.js | 33 +- .../walkthroughs/activeEntryWalkthrough.js | 42 +- 15 files changed, 997 insertions(+), 733 deletions(-) create mode 100755 Packages/active-entry/components/changePassword/changePassword.html create mode 100755 Packages/active-entry/components/changePassword/changePassword.js create mode 100755 Packages/active-entry/components/changePassword/changePassword.less diff --git a/LesionTracker/.meteor/versions b/LesionTracker/.meteor/versions index 5bb385199..4fab1ac80 100644 --- a/LesionTracker/.meteor/versions +++ b/LesionTracker/.meteor/versions @@ -16,7 +16,7 @@ caching-compiler@1.0.0 caching-html-compiler@1.0.2 callback-hook@1.0.4 check@1.1.0 -clinical:active-entry@1.5.15 +clinical:active-entry@1.5.16 clinical:auto-resizing@0.1.2 clinical:error-pages@0.1.1 clinical:extended-api@2.2.2 @@ -28,7 +28,6 @@ clinical:router-location@2.0.14 clinical:router-middleware-stack@2.0.13 clinical:router-url@2.0.15 clinical:theming@0.4.7 -codetheweb:zxcvbn@4.0.1 coffeescript@1.0.11 cornerstone@0.0.1 ddp@1.2.2 diff --git a/LesionTracker/activeEntry.js b/LesionTracker/activeEntry.js index 51a196b62..48cb0cafc 100644 --- a/LesionTracker/activeEntry.js +++ b/LesionTracker/activeEntry.js @@ -15,8 +15,9 @@ if (Meteor.isClient){ primary: "" }, passwordOptions: { - requireStrongPasswords: true, - showPasswordStrengthIndicator: true + showPasswordStrengthIndicator: true, + requireRegexValidation: true + //requireStrongPasswords: false } }); } diff --git a/Packages/active-entry/Contributing.md b/Packages/active-entry/Contributing.md index bcfbe714a..aa34713b2 100644 --- a/Packages/active-entry/Contributing.md +++ b/Packages/active-entry/Contributing.md @@ -1,5 +1,10 @@ ## Contributing +**Submit your Pull Request on a Feature Branch** + +- To ensure your pull-request has the greatest chance of getting merged in, please submit it on a feature branch rather than directly to master. +- Please see [A successful Git branching model](http://nvie.com/posts/a-successful-git-branching-model/) for more details. + **Quality Assurance** - Pull Requests will be generally accepted as long as the QA tests pass on [Circle CI](https://circleci.com/gh/clinical-meteor/clinical-active-entry). - Begin a Pull Request by logging an Issue for discussion. diff --git a/Packages/active-entry/circle.yml b/Packages/active-entry/circle.yml index 16a78dee3..f4a45a711 100644 --- a/Packages/active-entry/circle.yml +++ b/Packages/active-entry/circle.yml @@ -1,5 +1,7 @@ ## Customize the test machine machine: + node: + version: 0.10.33 # Timezone timezone: @@ -25,27 +27,48 @@ checkout: ## Customize dependencies dependencies: cache_directories: - - "~/.meteor" # relative to the user's home directory + - ~/.meteor # relative to the user's home directory + - ~/nvm/v0.10.33/lib/node_modules/starrynight + - ~/nvm/v0.10.33/bin/starrynight + + pre: + # Install Starrynight unless it is cached + - if [ ! -e ~/nvm/v0.10.33/bin/starrynight ]; then npm install -g starrynight; else echo "Starrynight seems to be cached"; fi; + # Install Meteor + - mkdir -p ${HOME}/.meteor + # If Meteor is already cached, do not need to build it again. + - if [ ! -e ${HOME}/.meteor/meteor ]; then curl https://install.meteor.com | /bin/sh; else echo "Meteor seems to be cached"; fi; + # Link the meteor executable into /usr/bin + - sudo ln -s $HOME/.meteor/meteor /usr/bin/meteor + # Check if the helloworld directory already exists, if it doesn't, create the helloworld app + # The following doesn't work, because it should be checking ${HOME}/active-entry/helloworld + # - if [ ! -e ${HOME}/helloworld ]; then meteor create --release METEOR@1.1.0.3 helloworld; else echo "helloworld app seems to be cached"; fi; override: - - meteor || curl https://install.meteor.com | /bin/sh - - npm install starrynight -g - - meteor create --release METEOR@1.1.0.3 helloworld - - cd helloworld - - cd helloworld && ls -la - - cd helloworld && rm helloworld.* - - cd helloworld && meteor add anti:gagarin@0.4.11 accounts-base accounts-password session meteor-platform clinical:active-entry clinical:user-model - - cd helloworld && git clone http://github.com/clinical-meteor/clinical-active-entry packages/active-entry - - cd helloworld && starrynight autoconfig + - cd ${HOME} && meteor create --release METEOR@1.1.0.3 helloworld + - cd ${HOME}/helloworld + - cd ${HOME}/helloworld && ls -la + - cd ${HOME}/helloworld && rm helloworld.* + - cd ${HOME}/helloworld && mkdir packages && mkdir packages/active-entry + - cp -R * ${HOME}/helloworld/packages/active-entry + - cd ${HOME}/helloworld && meteor add anti:gagarin@0.4.11 accounts-base accounts-password session meteor-platform clinical:user-model clinical:active-entry + - cd ${HOME}/helloworld && starrynight autoconfig + - cd ${HOME}/helloworld && meteor list + - cat tests/gagarin/activeEntryTests.js + - ls -la + - cd ~ && ls -la + - cd ${HOME} && pwd + - cd ${HOME} && ls -la + - cd ${HOME}/helloworld && ls -la ## Customize test commands test: pre: - cd helloworld && meteor: background: true - - sleep 80 + - sleep 30 override: - - cd helloworld && starrynight run-tests --type package-verification + - cd ${HOME}/helloworld && starrynight run-tests --type package-verification ## Customize deployment commands #deployment: diff --git a/Packages/active-entry/components/changePassword/changePassword.html b/Packages/active-entry/components/changePassword/changePassword.html new file mode 100755 index 000000000..add5897aa --- /dev/null +++ b/Packages/active-entry/components/changePassword/changePassword.html @@ -0,0 +1,40 @@ + diff --git a/Packages/active-entry/components/changePassword/changePassword.js b/Packages/active-entry/components/changePassword/changePassword.js new file mode 100755 index 000000000..cf0c56a4d --- /dev/null +++ b/Packages/active-entry/components/changePassword/changePassword.js @@ -0,0 +1,84 @@ +//========================================== + +Router.route('/changePassword', { + name: "changePassword", + template: "changePassword" +}); + + +Template.changePassword.helpers({ + getChangePasswordMessageColor: function (){ + if (ActiveEntry.errorMessages.get('changePasswordError')) { + return "color: #a94442; background-color: #f2dede; border-color: #ebccd1;" + } else { + return "color: black;" + } + }, + getChangePasswordMessage: function (){ + if (ActiveEntry.errorMessages.get('changePasswordError')) { + return ActiveEntry.errorMessages.get('changePasswordError'); + } else { + return Session.get('defaultSignInMessage'); + } + }, + getPasswordStyling: function () { + if (ActiveEntry.errorMessages.equals('password', "Password is required")) { + return "border: 1px solid #a94442"; + } else if (ActiveEntry.errorMessages.equals('password', "Password is weak")) { + return "border: 1px solid #f2dede"; + } else if (ActiveEntry.errorMessages.equals('password', "Password present")) { + return "border: 1px solid green"; + } else { + return "border: 1px solid gray"; + } + }, + getConfirmPasswordStyling: function () { + if (ActiveEntry.errorMessages.equals('confirm', "Password is required")) { + return "border: 1px solid #a94442"; + } else if (ActiveEntry.errorMessages.equals('confirm', "Passwords do not match")) { + return "border: 1px solid #a94442"; + } else if (ActiveEntry.errorMessages.equals('confirm', "Password is weak")) { + return "border: 1px solid #f2dede"; + } else if (ActiveEntry.errorMessages.equals('confirm', "Passwords match")) { + return "border: 1px solid green"; + } else { + return "border: 1px solid gray"; + } + } +}); + +Template.changePassword.events({ + 'change, keyup #changePasswordPagePasswordInput': function (event, template) { + var password = $('[name="password"]').val(); + var confirmPassword = $('[name="confirm"]').val(); + + ActiveEntry.verifyPassword(password); + ActiveEntry.errorMessages.set('changePasswordError', null); + }, + 'change, keyup #changePasswordPagePasswordConfirmInput': function (event, template) { + var password = $('[name="password"]').val(); + var confirmPassword = $('[name="confirm"]').val(); + + ActiveEntry.verifyConfirmPassword(password, confirmPassword); + ActiveEntry.errorMessages.set('changePasswordError', null); + }, + "submit": function (event, template) { + event.preventDefault(); + + var oldPassword = $('[name="oldPassword"]').val(); + + var password = $('[name="password"]').val(); + var confirmPassword = $('[name="confirm"]').val(); + + ActiveEntry.verifyConfirmPassword(password, confirmPassword); + ActiveEntry.errorMessages.set('changePasswordError', null); + + Accounts.changePassword(oldPassword, confirmPassword, function(error) { + if (error) { + console.warn(error); + return; + } + console.log('Password changed!'); + }); + } +}); diff --git a/Packages/active-entry/components/changePassword/changePassword.less b/Packages/active-entry/components/changePassword/changePassword.less new file mode 100755 index 000000000..b68dbb62c --- /dev/null +++ b/Packages/active-entry/components/changePassword/changePassword.less @@ -0,0 +1,5 @@ +#changePassword{ + input{ + padding-left: 40px; + } +} diff --git a/Packages/active-entry/components/entrySignIn/entrySignIn.js b/Packages/active-entry/components/entrySignIn/entrySignIn.js index 3320925fc..c6420a56f 100755 --- a/Packages/active-entry/components/entrySignIn/entrySignIn.js +++ b/Packages/active-entry/components/entrySignIn/entrySignIn.js @@ -126,14 +126,13 @@ Template.entrySignIn.events({ ActiveEntry.signIn(emailValue, passwordValue); event.preventDefault(); }, - 'keypress #entrySignIn': function(event, template) { + 'keyup #entrySignIn': function(event, template) { if(event.keyCode == 13) { ActiveEntry.verifyEmail($("#signInPageEmailInput").val()); - ActiveEntry.verifyPassword($("#signInPagePasswordInput").val()); if (!ActiveEntry.errorMessages.get('signInError') && ActiveEntry.successMessages.get('email') && - ActiveEntry.successMessages.get('password')) { + $("#signInPagePasswordInput").val()) { $("#signInToAppButton").click(); } } diff --git a/Packages/active-entry/components/entrySignUp/entrySignUp.js b/Packages/active-entry/components/entrySignUp/entrySignUp.js index 6a713c283..0bdddb3a4 100755 --- a/Packages/active-entry/components/entrySignUp/entrySignUp.js +++ b/Packages/active-entry/components/entrySignUp/entrySignUp.js @@ -71,6 +71,8 @@ Template.entrySignUp.helpers({ if (ActiveEntry.errorMessages.equals('confirm', "Password is required")) { return "border: 1px solid #a94442"; } else if (ActiveEntry.errorMessages.equals('confirm', "Passwords do not match")) { + return "border: 1px solid #a94442"; + } else if (ActiveEntry.errorMessages.equals('confirm', "Password is weak")) { return "border: 1px solid #f2dede"; } else if (ActiveEntry.successMessages.equals('confirm', "Passwords match")) { return "border: 1px solid green"; @@ -133,7 +135,7 @@ Template.entrySignUp.events({ $('#signUpPageFullNameInput').val() ); }, - 'keypress #entrySignUp': function(event, template) { + 'keyup #entrySignUp': function(event, template) { if(event.keyCode == 13) { ActiveEntry.verifyFullName($("#signUpPageFullNameInput").val()); ActiveEntry.verifyEmail($("#signUpPageEmailInput").val()); @@ -153,13 +155,12 @@ Template.entrySignUp.events({ Template.entrySignUp.onRendered(function() { // Password strength meter for password inputs - if (passwordValidationSettings.requireStrongPasswords) { + if (passwordValidationSettings.showPasswordStrengthIndicator) { this.$('#signUpPagePasswordInput').pwstrength(passwordValidationSettings.pwstrengthOptions); } - // Update password warning message if zxcvbn is active - if(passwordValidationSettings.showPasswordStrengthIndicator) { + // Update password warning message if zxcvbn is active and zxcvbn function is defined + if(passwordValidationSettings.requireStrongPasswords) { Session.set('passwordWarning', 'Password is weak'); } }); - diff --git a/Packages/active-entry/lib/ActiveEntry.js b/Packages/active-entry/lib/ActiveEntry.js index 4dfa23f86..83710f7d9 100755 --- a/Packages/active-entry/lib/ActiveEntry.js +++ b/Packages/active-entry/lib/ActiveEntry.js @@ -24,12 +24,15 @@ if (Meteor.isClient) { primary: "" }, passwordOptions: { - requireStrongPasswords: false, - showPasswordStrengthIndicator: false + showPasswordStrengthIndicator: true, + requireRegexValidation: true + //requireStrongPasswords: false } }); } +// requireRegexValidation toggles regex +// reqiureStrongPasswords toggles zxcvbn if (Meteor.isClient) { ActiveEntry.errorMessages = new ReactiveDict('errorMessages'); @@ -56,7 +59,6 @@ ActiveEntry.verifyPassword = function (password) { ActiveEntry.errorMessages.set('password', Session.get('passwordWarning')); ActiveEntry.successMessages.set('password', null); } else { - //ActiveEntry.errorMessages.set('password', 'Password present'); ActiveEntry.errorMessages.set('password', null); ActiveEntry.successMessages.set('password', 'Password present'); } @@ -64,11 +66,15 @@ ActiveEntry.verifyPassword = function (password) { }; ActiveEntry.verifyConfirmPassword = function (password, confirmPassword) { - if (confirmPassword === password) { - //ActiveEntry.errorMessages.set('confirm', 'Passwords match'); + // we have two different logic checks happening in this function + // would be reasonable to separate them out into separate functions + if (confirmPassword === "") { + ActiveEntry.errorMessages.set('confirm', 'Password is required'); + ActiveEntry.successMessages.set('confirm', null); + } else if (confirmPassword === password) { ActiveEntry.errorMessages.set('confirm', null); ActiveEntry.successMessages.set('confirm', 'Passwords match'); - } else{ + } else { ActiveEntry.errorMessages.set('confirm', 'Passwords do not match'); ActiveEntry.successMessages.set('confirm', null); } diff --git a/Packages/active-entry/lib/checkPasswordStrength.js b/Packages/active-entry/lib/checkPasswordStrength.js index 9915f6e6a..a36b45887 100644 --- a/Packages/active-entry/lib/checkPasswordStrength.js +++ b/Packages/active-entry/lib/checkPasswordStrength.js @@ -1,46 +1,59 @@ passwordValidationSettings = {}; -var ActiveEntryConfiguration; -Meteor.startup(function() { - ActiveEntryConfiguration = Session.get('Photonic.ActiveEntry'); - var showPasswordStrengthIndicator = (ActiveEntryConfiguration && ActiveEntryConfiguration.passwordOptions && ActiveEntryConfiguration.passwordOptions.showPasswordStrengthIndicator || false); - passwordValidationSettings.requireStrongPasswords = (ActiveEntryConfiguration && ActiveEntryConfiguration.passwordOptions && ActiveEntryConfiguration.passwordOptions.requireStrongPasswords || false); - passwordValidationSettings.showPasswordStrengthIndicator = showPasswordStrengthIndicator; - passwordValidationSettings.pwstrengthOptions = { - common: { - minChar: 8, - zxcvbn: showPasswordStrengthIndicator - }, - ui: { - showVerdictsInsideProgressBar: true, - showStatus: true - }, - rules: { - activated: { - wordNotEmail: true, - wordTwoCharacterClasses: true, - wordRepetitions: true +function getPasswordValidationSettings () { + var ActiveEntryConfiguration = Session.get('Photonic.ActiveEntry'); + var validationSettings = {}; + + validationSettings.showPasswordStrengthIndicator = ActiveEntryConfiguration && ActiveEntryConfiguration.passwordOptions && ActiveEntryConfiguration.passwordOptions.showPasswordStrengthIndicator || false; + validationSettings.requireRegexValidation = ActiveEntryConfiguration && ActiveEntryConfiguration.passwordOptions && ActiveEntryConfiguration.passwordOptions.requireRegexValidation || false; + + if (validationSettings.showPasswordStrengthIndicator) { + // Set password strength meter options + validationSettings.pwstrengthOptions = { + common: { + minChar: 8 + }, + ui: { + showVerdictsInsideProgressBar: true, + showStatus: true } + }; + } + + // Check if codetheweb:zxcvbn is defined + if (typeof(zxcvbn) === typeof(Function)) { + validationSettings.requireStrongPasswords = ActiveEntryConfiguration && ActiveEntryConfiguration.passwordOptions && ActiveEntryConfiguration.passwordOptions.requireStrongPasswords || false; + // Set zxcvbn in pw strength meter + if (validationSettings.showPasswordStrengthIndicator) { + validationSettings.pwstrengthOptions.common.zxcvbn = passwordValidationSettings.requireStrongPasswords; } - }; + } + + return validationSettings; +} + +Meteor.startup(function() { + passwordValidationSettings = getPasswordValidationSettings(); }); -// Check Password Strength: at least 8 characters in length and contain at least 1 uppercase, 1 lowercase and 1 number and 1 special character checkPasswordStrength = function(password) { - var iszxcvbnActive = (ActiveEntryConfiguration && ActiveEntryConfiguration.passwordOptions && ActiveEntryConfiguration.passwordOptions.showPasswordStrengthIndicator || false); - if (iszxcvbnActive) { - // Check zxcvbn rule + if (passwordValidationSettings.requireStrongPasswords) { + // Check zxcvbn var zxcvbnResult = zxcvbn(password); - if (zxcvbnResult.score > 2) { + if (zxcvbnResult && zxcvbnResult.score > 2) { return true; } - } else{ + + return false; + } else if (passwordValidationSettings.requireRegexValidation) { // Apply validation rule var result = password.search(/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&*])[0-9a-zA-Z!@#$%^&*]{8,}$/i); if (result > -1) { return true; } + + return false; } - return false; + return true; }; \ No newline at end of file diff --git a/Packages/active-entry/lib/jquery.pwstrength.bootstrap.js b/Packages/active-entry/lib/jquery.pwstrength.bootstrap.js index ce466d7fe..ddaaf1568 100644 --- a/Packages/active-entry/lib/jquery.pwstrength.bootstrap.js +++ b/Packages/active-entry/lib/jquery.pwstrength.bootstrap.js @@ -7,702 +7,731 @@ */ (function (jQuery) { -// Source: src/rules.js + // Source: src/rules.js + var rulesEngine = {}; - var rulesEngine = {}; + try { + if (!jQuery && module && module.exports) { + var jQuery = require("jquery"), + jsdom = require("jsdom").jsdom; + jQuery = jQuery(jsdom().parentWindow); + } + } catch (ignore) {} - try { - if (!jQuery && module && module.exports) { - var jQuery = require("jquery"), - jsdom = require("jsdom").jsdom; - jQuery = jQuery(jsdom().parentWindow); - } - } catch (ignore) {} + (function ($, rulesEngine) { + "use strict"; + var validation = {}; - (function ($, rulesEngine) { - "use strict"; - var validation = {}; - - rulesEngine.forbiddenSequences = [ + rulesEngine.forbiddenSequences = [ "0123456789", "abcdefghijklmnopqrstuvwxyz", "qwertyuiop", "asdfghjkl", "zxcvbnm", "!@#$%^&*()_+" ]; - validation.wordNotEmail = function (options, word, score) { - if (word.match(/^([\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*[\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+@((((([a-z0-9]{1}[a-z0-9\-]{0,62}[a-z0-9]{1})|[a-z])\.)+[a-z]{2,6})|(\d{1,3}\.){3}\d{1,3}(\:\d{1,5})?)$/i)) { - return score; + validation.wordNotEmail = function (options, word, score) { + if (word.match( + /^([\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*[\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+@((((([a-z0-9]{1}[a-z0-9\-]{0,62}[a-z0-9]{1})|[a-z])\.)+[a-z]{2,6})|(\d{1,3}\.){3}\d{1,3}(\:\d{1,5})?)$/i + )) { + return score; + } + return 0; + }; + + validation.wordLength = function (options, word, score) { + var wordlen = word.length, + lenScore = Math.pow(wordlen, options.rules.raisePower); + if (wordlen < options.common.minChar) { + lenScore = (lenScore + score); + } + return lenScore; + }; + + validation.wordSimilarToUsername = function (options, word, score) { + var username = $(options.common.usernameField).val(); + if (username && word.toLowerCase().match(username.replace( + /[\-\[\]\/\{\}\(\)\*\+\=\?\:\.\\\^\$\|\!\,]/g, "\\$&").toLowerCase())) { + return score; + } + return 0; + }; + + validation.wordTwoCharacterClasses = function (options, word, score) { + if (word.match(/([a-z].*[A-Z])|([A-Z].*[a-z])/) || + (word.match(/([a-zA-Z])/) && word.match(/([0-9])/)) || + (word.match(/(.[!,@,#,$,%,\^,&,*,?,_,~])/) && word.match(/[a-zA-Z0-9_]/))) { + return score; + } + return 0; + }; + + validation.wordRepetitions = function (options, word, score) { + if (word.match(/(.)\1\1/)) { + return score; + } + return 0; + }; + + validation.wordSequences = function (options, word, score) { + var found = false, + j; + if (word.length > 2) { + $.each(rulesEngine.forbiddenSequences, function (idx, seq) { + if (found) { + return; + } + var sequences = [seq, seq.split('').reverse().join('')]; + $.each(sequences, function (idx, sequence) { + for (j = 0; j < (word.length - 2); j += 1) { // iterate the word trough a sliding window of size 3: + if (sequence.indexOf(word.toLowerCase().substring(j, j + 3)) > -1) { + found = true; + } } - return 0; - }; - - validation.wordLength = function (options, word, score) { - var wordlen = word.length, - lenScore = Math.pow(wordlen, options.rules.raisePower); - if (wordlen < options.common.minChar) { - lenScore = (lenScore + score); - } - return lenScore; - }; - - validation.wordSimilarToUsername = function (options, word, score) { - var username = $(options.common.usernameField).val(); - if (username && word.toLowerCase().match(username.replace(/[\-\[\]\/\{\}\(\)\*\+\=\?\:\.\\\^\$\|\!\,]/g, "\\$&").toLowerCase())) { - return score; - } - return 0; - }; - - validation.wordTwoCharacterClasses = function (options, word, score) { - if (word.match(/([a-z].*[A-Z])|([A-Z].*[a-z])/) || - (word.match(/([a-zA-Z])/) && word.match(/([0-9])/)) || - (word.match(/(.[!,@,#,$,%,\^,&,*,?,_,~])/) && word.match(/[a-zA-Z0-9_]/))) { - return score; - } - return 0; - }; - - validation.wordRepetitions = function (options, word, score) { - if (word.match(/(.)\1\1/)) { return score; } - return 0; - }; - - validation.wordSequences = function (options, word, score) { - var found = false, - j; - if (word.length > 2) { - $.each(rulesEngine.forbiddenSequences, function (idx, seq) { - if (found) { return; } - var sequences = [seq, seq.split('').reverse().join('')]; - $.each(sequences, function (idx, sequence) { - for (j = 0; j < (word.length - 2); j += 1) { // iterate the word trough a sliding window of size 3: - if (sequence.indexOf(word.toLowerCase().substring(j, j + 3)) > -1) { - found = true; - } - } - }); - }); - if (found) { return score; } - } - return 0; - }; - - validation.wordLowercase = function (options, word, score) { - return word.match(/[a-z]/) && score; - }; - - validation.wordUppercase = function (options, word, score) { - return word.match(/[A-Z]/) && score; - }; - - validation.wordOneNumber = function (options, word, score) { - return word.match(/\d+/) && score; - }; - - validation.wordThreeNumbers = function (options, word, score) { - return word.match(/(.*[0-9].*[0-9].*[0-9])/) && score; - }; - - validation.wordOneSpecialChar = function (options, word, score) { - return word.match(/[!,@,#,$,%,\^,&,*,?,_,~]/) && score; - }; - - validation.wordTwoSpecialChar = function (options, word, score) { - return word.match(/(.*[!,@,#,$,%,\^,&,*,?,_,~].*[!,@,#,$,%,\^,&,*,?,_,~])/) && score; - }; - - validation.wordUpperLowerCombo = function (options, word, score) { - return word.match(/([a-z].*[A-Z])|([A-Z].*[a-z])/) && score; - }; - - validation.wordLetterNumberCombo = function (options, word, score) { - return word.match(/([a-zA-Z])/) && word.match(/([0-9])/) && score; - }; - - validation.wordLetterNumberCharCombo = function (options, word, score) { - return word.match(/([a-zA-Z0-9].*[!,@,#,$,%,\^,&,*,?,_,~])|([!,@,#,$,%,\^,&,*,?,_,~].*[a-zA-Z0-9])/) && score; - }; - - rulesEngine.validation = validation; - - rulesEngine.executeRules = function (options, word) { - var totalScore = 0; - - $.each(options.rules.activated, function (rule, active) { - if (active) { - var score = options.rules.scores[rule], - funct = rulesEngine.validation[rule], - result, - errorMessage; - - if (!$.isFunction(funct)) { - funct = options.rules.extra[rule]; - } - - if ($.isFunction(funct)) { - result = funct(options, word, score); - if (result) { - totalScore += result; - } - if (result < 0 || (!$.isNumeric(result) && !result)) { - errorMessage = options.ui.spanError(options, rule); - if (errorMessage.length > 0) { - options.instances.errors.push(errorMessage); - } - } - } - } - }); - - return totalScore; - }; - }(jQuery, rulesEngine)); - - try { - if (module && module.exports) { - module.exports = rulesEngine; + }); + }); + if (found) { + return score; } - } catch (ignore) {} + } + return 0; + }; -// Source: src/options.js + validation.wordLowercase = function (options, word, score) { + return word.match(/[a-z]/) && score; + }; + + validation.wordUppercase = function (options, word, score) { + return word.match(/[A-Z]/) && score; + }; + + validation.wordOneNumber = function (options, word, score) { + return word.match(/\d+/) && score; + }; + + validation.wordThreeNumbers = function (options, word, score) { + return word.match(/(.*[0-9].*[0-9].*[0-9])/) && score; + }; + + validation.wordOneSpecialChar = function (options, word, score) { + return word.match(/[!,@,#,$,%,\^,&,*,?,_,~]/) && score; + }; + + validation.wordTwoSpecialChar = function (options, word, score) { + return word.match(/(.*[!,@,#,$,%,\^,&,*,?,_,~].*[!,@,#,$,%,\^,&,*,?,_,~])/) && score; + }; + + validation.wordUpperLowerCombo = function (options, word, score) { + return word.match(/([a-z].*[A-Z])|([A-Z].*[a-z])/) && score; + }; + + validation.wordLetterNumberCombo = function (options, word, score) { + return word.match(/([a-zA-Z])/) && word.match(/([0-9])/) && score; + }; + + validation.wordLetterNumberCharCombo = function (options, word, score) { + return word.match( + /([a-zA-Z0-9].*[!,@,#,$,%,\^,&,*,?,_,~])|([!,@,#,$,%,\^,&,*,?,_,~].*[a-zA-Z0-9])/) && + score; + }; + + rulesEngine.validation = validation; + + rulesEngine.executeRules = function (options, word) { + var totalScore = 0; + + $.each(options.rules.activated, function (rule, active) { + if (active) { + var score = options.rules.scores[rule], + funct = rulesEngine.validation[rule], + result, + errorMessage; + + if (!$.isFunction(funct)) { + funct = options.rules.extra[rule]; + } + + if ($.isFunction(funct)) { + result = funct(options, word, score); + if (result) { + totalScore += result; + } + if (result < 0 || (!$.isNumeric(result) && !result)) { + errorMessage = options.ui.spanError(options, rule); + if (errorMessage.length > 0) { + options.instances.errors.push(errorMessage); + } + } + } + } + }); + + return totalScore; + }; + }(jQuery, rulesEngine)); + + try { + if (module && module.exports) { + module.exports = rulesEngine; + } + } catch (ignore) {} + + // Source: src/options.js + var defaultOptions = {}; - var defaultOptions = {}; - - defaultOptions.common = {}; - defaultOptions.common.minChar = 6; - defaultOptions.common.usernameField = "#username"; - defaultOptions.common.userInputs = [ + defaultOptions.common = {}; + defaultOptions.common.minChar = 6; + defaultOptions.common.usernameField = "#username"; + defaultOptions.common.userInputs = [ // Selectors for input fields with user input ]; - defaultOptions.common.onLoad = undefined; - defaultOptions.common.onKeyUp = undefined; - defaultOptions.common.zxcvbn = false; - defaultOptions.common.zxcvbnTerms = [ + defaultOptions.common.onLoad = undefined; + defaultOptions.common.onKeyUp = undefined; + defaultOptions.common.zxcvbn = false; + defaultOptions.common.zxcvbnTerms = [ // List of disrecommended words ]; - defaultOptions.common.debug = false; + defaultOptions.common.debug = false; - defaultOptions.rules = {}; - defaultOptions.rules.extra = {}; - defaultOptions.rules.scores = { - wordNotEmail: -100, - wordLength: -50, - wordSimilarToUsername: -100, - wordSequences: -20, - wordTwoCharacterClasses: 2, - wordRepetitions: -25, - wordLowercase: 1, - wordUppercase: 3, - wordOneNumber: 3, - wordThreeNumbers: 5, - wordOneSpecialChar: 3, - wordTwoSpecialChar: 5, - wordUpperLowerCombo: 2, - wordLetterNumberCombo: 2, - wordLetterNumberCharCombo: 2 - }; - defaultOptions.rules.activated = { - wordNotEmail: true, - wordLength: true, - wordSimilarToUsername: true, - wordSequences: true, - wordTwoCharacterClasses: false, - wordRepetitions: false, - wordLowercase: true, - wordUppercase: true, - wordOneNumber: true, - wordThreeNumbers: true, - wordOneSpecialChar: true, - wordTwoSpecialChar: true, - wordUpperLowerCombo: true, - wordLetterNumberCombo: true, - wordLetterNumberCharCombo: true - }; - defaultOptions.rules.raisePower = 1.4; + defaultOptions.rules = {}; + defaultOptions.rules.extra = {}; + defaultOptions.rules.scores = { + wordNotEmail: -100, + wordLength: -50, + wordSimilarToUsername: -100, + wordSequences: -20, + wordTwoCharacterClasses: 2, + wordRepetitions: -25, + wordLowercase: 1, + wordUppercase: 3, + wordOneNumber: 3, + wordThreeNumbers: 5, + wordOneSpecialChar: 3, + wordTwoSpecialChar: 5, + wordUpperLowerCombo: 2, + wordLetterNumberCombo: 2, + wordLetterNumberCharCombo: 2 + }; + defaultOptions.rules.activated = { + wordNotEmail: true, + wordLength: true, + wordSimilarToUsername: true, + wordSequences: true, + wordTwoCharacterClasses: false, + wordRepetitions: false, + wordLowercase: true, + wordUppercase: true, + wordOneNumber: true, + wordThreeNumbers: true, + wordOneSpecialChar: true, + wordTwoSpecialChar: true, + wordUpperLowerCombo: true, + wordLetterNumberCombo: true, + wordLetterNumberCharCombo: true + }; + defaultOptions.rules.raisePower = 1.4; - defaultOptions.ui = {}; - defaultOptions.ui.bootstrap2 = false; - defaultOptions.ui.bootstrap4 = false; - defaultOptions.ui.colorClasses = ["danger", "warning", "success"]; - defaultOptions.ui.showProgressBar = true; - defaultOptions.ui.showPopover = false; - defaultOptions.ui.popoverPlacement = "bottom"; - defaultOptions.ui.showStatus = false; - defaultOptions.ui.spanError = function (options, key) { - "use strict"; - var text = options.ui.errorMessages[key]; - if (!text) { return ''; } - return '' + text + ''; - }; - defaultOptions.ui.popoverError = function (errors) { - "use strict"; - var message = "
Errors:
"; - return message; + } }; - defaultOptions.ui.errorMessages = { - wordLength: "Your password is too short", - wordNotEmail: "Do not use your email as your password", - wordSimilarToUsername: "Your password cannot contain your username", - wordTwoCharacterClasses: "Use different character classes", - wordRepetitions: "Too many repetitions", - wordSequences: "Your password contains sequences" + + methods.init = function (settings) { + this.each(function (idx, el) { + // Make it deep extend (first param) so it extends too the + // rules and other inside objects + var clonedDefaults = $.extend(true, {}, defaultOptions), + localOptions = $.extend(true, clonedDefaults, settings), + $el = $(el); + + localOptions.instances = {}; + $el.data("pwstrength-bootstrap", localOptions); + $el.on("keyup", onKeyUp); + $el.on("change", onKeyUp); + $el.on("paste", onKeyUp); + + ui.initUI(localOptions, $el); + if ($.trim($el.val())) { // Not empty, calculate the strength + $el.trigger("keyup"); + } + + if ($.isFunction(localOptions.common.onLoad)) { + localOptions.common.onLoad(); + } + }); + + return this; }; - defaultOptions.ui.verdicts = ["Weak", "Normal", "Medium", "Strong", "Very Strong"]; - defaultOptions.ui.showVerdicts = true; - defaultOptions.ui.showVerdictsInsideProgressBar = false; - defaultOptions.ui.useVerdictCssClass = false; - defaultOptions.ui.showErrors = false; - defaultOptions.ui.container = undefined; - defaultOptions.ui.viewports = { - progress: undefined, - verdict: undefined, - errors: undefined + + methods.destroy = function () { + this.each(function (idx, el) { + var $el = $(el), + options = $el.data("pwstrength-bootstrap"), + elements = ui.getUIElements(options, $el); + elements.$progressbar.remove(); + elements.$verdict.remove(); + elements.$errors.remove(); + $el.removeData("pwstrength-bootstrap"); + }); }; - defaultOptions.ui.scores = [14, 26, 38, 50]; -// Source: src/ui.js - - - - - var ui = {}; - - (function ($, ui) { - "use strict"; - - var statusClasses = ["error", "warning", "success"]; - - ui.getContainer = function (options, $el) { - var $container; - - $container = $(options.ui.container); - if (!($container && $container.length === 1)) { - $container = $el.parent(); - } - return $container; + methods.forceUpdate = function () { + this.each(function (idx, el) { + var event = { + target: el }; + onKeyUp(event); + }); + }; - ui.findElement = function ($container, viewport, cssSelector) { - if (viewport) { - return $container.find(viewport).find(cssSelector); - } - return $container.find(cssSelector); - }; + methods.addRule = function (name, method, score, active) { + this.each(function (idx, el) { + var options = $(el).data("pwstrength-bootstrap"); - ui.getUIElements = function (options, $el) { - var $container, selector, result; + options.rules.activated[name] = active; + options.rules.scores[name] = score; + options.rules.extra[name] = method; + }); + }; - if (options.instances.viewports) { - return options.instances.viewports; - } + applyToAll = function (rule, prop, value) { + this.each(function (idx, el) { + $(el).data("pwstrength-bootstrap").rules[prop][rule] = value; + }); + }; - $container = ui.getContainer(options, $el); + methods.changeScore = function (rule, score) { + applyToAll.call(this, rule, "scores", score); + }; - result = {}; - if (options.ui.bootstrap4) { - selector = "progress.progress"; - } else { - selector = "div.progress"; - } - result.$progressbar = ui.findElement($container, options.ui.viewports.progress, selector); - if (options.ui.showVerdictsInsideProgressBar) { - result.$verdict = result.$progressbar.find("span.password-verdict"); - } + methods.ruleActive = function (rule, active) { + applyToAll.call(this, rule, "activated", active); + }; - if (!options.ui.showPopover) { - if (!options.ui.showVerdictsInsideProgressBar) { - result.$verdict = ui.findElement($container, options.ui.viewports.verdict, "span.password-verdict"); - } - result.$errors = ui.findElement($container, options.ui.viewports.errors, "ul.error-list"); - } + $.fn.pwstrength = function (method) { + var result; - options.instances.viewports = result; - return result; - }; + if (methods[method]) { + result = methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); + } else if (typeof method === "object" || !method) { + result = methods.init.apply(this, arguments); + } else { + $.error("Method " + method + " does not exist on jQuery.pwstrength-bootstrap"); + } - ui.initProgressBar = function (options, $el) { - var $container = ui.getContainer(options, $el), - progressbar = "
"; - if (options.ui.bootstrap4) { - // Boostrap 4 - progressbar = ""; - } - if (options.ui.showVerdictsInsideProgressBar) { - progressbar += ""; - } - if (options.ui.bootstrap4) { - progressbar += ""; - } else { - progressbar += "
"; - } - - if (options.ui.viewports.progress) { - $container.find(options.ui.viewports.progress).append(progressbar); - } else { - $(progressbar).insertAfter($el); - } - }; - - ui.initHelper = function (options, $el, html, viewport) { - var $container = ui.getContainer(options, $el); - if (viewport) { - $container.find(viewport).append(html); - } else { - $(html).insertAfter($el); - } - }; - - ui.initVerdict = function (options, $el) { - ui.initHelper(options, $el, "", - options.ui.viewports.verdict); - }; - - ui.initErrorList = function (options, $el) { - ui.initHelper(options, $el, "", - options.ui.viewports.errors); - }; - - ui.initPopover = function (options, $el) { - $el.popover("destroy"); - $el.popover({ - html: true, - placement: options.ui.popoverPlacement, - trigger: "manual", - content: " " - }); - }; - - ui.initUI = function (options, $el) { - if (options.ui.showPopover) { - ui.initPopover(options, $el); - } else { - if (options.ui.showErrors) { ui.initErrorList(options, $el); } - if (options.ui.showVerdicts && !options.ui.showVerdictsInsideProgressBar) { - ui.initVerdict(options, $el); - } - } - if (options.ui.showProgressBar) { - ui.initProgressBar(options, $el); - } - }; - - ui.updateProgressBar = function (options, $el, cssClass, percentage) { - var $progressbar = ui.getUIElements(options, $el).$progressbar, - $bar = $progressbar.find(".progress-bar"), - cssPrefix = "progress-"; - - if (options.ui.bootstrap2) { - $bar = $progressbar.find(".bar"); - cssPrefix = ""; - } - - $.each(options.ui.colorClasses, function (idx, value) { - if (options.ui.bootstrap4) { - $progressbar.removeClass(cssPrefix + value); - } else { - $bar.removeClass(cssPrefix + "bar-" + value); - } - }); - if (options.ui.bootstrap4) { - $progressbar.addClass(cssPrefix + options.ui.colorClasses[cssClass]); - $progressbar.val(percentage); - } else { - $bar.addClass(cssPrefix + "bar-" + options.ui.colorClasses[cssClass]); - $bar.css("width", percentage + '%'); - } - }; - - ui.updateVerdict = function (options, $el, cssClass, text) { - var $verdict = ui.getUIElements(options, $el).$verdict; - $verdict.removeClass(options.ui.colorClasses.join(' ')); - if (cssClass > -1) { - $verdict.addClass(options.ui.colorClasses[cssClass]); - } - $verdict.html(text); - }; - - ui.updateErrors = function (options, $el) { - var $errors = ui.getUIElements(options, $el).$errors, - html = ""; - $.each(options.instances.errors, function (idx, err) { - html += "
  • " + err + "
  • "; - }); - $errors.html(html); - }; - - ui.updatePopover = function (options, $el, verdictText) { - var popover = $el.data("bs.popover"), - html = "", - hide = true; - - if (options.ui.showVerdicts && - !options.ui.showVerdictsInsideProgressBar && - verdictText.length > 0) { - html = "
    " + verdictText + - "
    "; - hide = false; - } - if (options.ui.showErrors) { - if (options.instances.errors.length > 0) { - hide = false; - } - html += options.ui.popoverError(options.instances.errors); - } - - if (hide) { - $el.popover("hide"); - return; - } - - if (options.ui.bootstrap2) { popover = $el.data("popover"); } - - if (popover.$arrow && popover.$arrow.parents("body").length > 0) { - $el.find("+ .popover .popover-content").html(html); - } else { - // It's hidden - popover.options.content = html; - $el.popover("show"); - } - }; - - ui.updateFieldStatus = function (options, $el, cssClass) { - var targetClass = options.ui.bootstrap2 ? ".control-group" : ".form-group", - $container = $el.parents(targetClass).first(); - - $.each(statusClasses, function (idx, css) { - if (!options.ui.bootstrap2) { css = "has-" + css; } - $container.removeClass(css); - }); - - cssClass = statusClasses[cssClass]; - if (!options.ui.bootstrap2) { cssClass = "has-" + cssClass; } - $container.addClass(cssClass); - }; - - ui.percentage = function (score, maximun) { - var result = Math.floor(100 * score / maximun); - result = result <= 0 ? 1 : result; // Don't show the progress bar empty - result = result > 100 ? 100 : result; - return result; - }; - - ui.getVerdictAndCssClass = function (options, score) { - var cssClass, verdictText, level; - - if (score <= 0) { - cssClass = 0; - level = -1; - verdictText = options.ui.verdicts[0]; - } else if (score < options.ui.scores[0]) { - cssClass = 0; - level = 0; - verdictText = options.ui.verdicts[0]; - } else if (score < options.ui.scores[1]) { - cssClass = 0; - level = 1; - verdictText = options.ui.verdicts[1]; - } else if (score < options.ui.scores[2]) { - cssClass = 1; - level = 2; - verdictText = options.ui.verdicts[2]; - } else if (score < options.ui.scores[3]) { - cssClass = 1; - level = 3; - verdictText = options.ui.verdicts[3]; - } else { - cssClass = 2; - level = 4; - verdictText = options.ui.verdicts[4]; - } - - return [verdictText, cssClass, level]; - }; - - ui.updateUI = function (options, $el, score) { - var cssClass, barPercentage, verdictText, verdictCssClass; - - cssClass = ui.getVerdictAndCssClass(options, score); - verdictText = score === 0 ? '' : cssClass[0]; - cssClass = cssClass[1]; - verdictCssClass = options.ui.useVerdictCssClass ? cssClass : -1; - - if (options.ui.showProgressBar) { - barPercentage = ui.percentage(score, options.ui.scores[3]); - ui.updateProgressBar(options, $el, cssClass, barPercentage); - if (options.ui.showVerdictsInsideProgressBar) { - ui.updateVerdict(options, $el, verdictCssClass, verdictText); - } - } - - if (options.ui.showStatus) { - ui.updateFieldStatus(options, $el, cssClass); - } - - if (options.ui.showPopover) { - ui.updatePopover(options, $el, verdictText); - } else { - if (options.ui.showVerdicts && !options.ui.showVerdictsInsideProgressBar) { - ui.updateVerdict(options, $el, verdictCssClass, verdictText); - } - if (options.ui.showErrors) { - ui.updateErrors(options, $el); - } - } - }; - }(jQuery, ui)); - -// Source: src/methods.js - - - - - var methods = {}; - - (function ($, methods) { - "use strict"; - var onKeyUp, applyToAll; - - onKeyUp = function (event) { - var $el = $(event.target), - options = $el.data("pwstrength-bootstrap"), - word = $el.val(), - userInputs, - verdictText, - verdictLevel, - score; - - if (options === undefined) { return; } - - options.instances.errors = []; - if (word.length === 0) { - score = 0; - } else { - if (options.common.zxcvbn) { - userInputs = []; - $.each(options.common.userInputs.concat([options.common.usernameField]), function (idx, selector) { - var value = $(selector).val(); - if (value) { userInputs.push(value); } - }); - userInputs = userInputs.concat(options.common.zxcvbnTerms); - score = Math.log2(zxcvbn(word, userInputs).guesses); - } else { - score = rulesEngine.executeRules(options, word); - } - } - ui.updateUI(options, $el, score); - verdictText = ui.getVerdictAndCssClass(options, score); - verdictLevel = verdictText[2]; - verdictText = verdictText[0]; - - if (options.common.debug) { console.log(score + ' - ' + verdictText); } - - if ($.isFunction(options.common.onKeyUp)) { - options.common.onKeyUp(event, { - score: score, - verdictText: verdictText, - verdictLevel: verdictLevel - }); - } - }; - - methods.init = function (settings) { - this.each(function (idx, el) { - // Make it deep extend (first param) so it extends too the - // rules and other inside objects - var clonedDefaults = $.extend(true, {}, defaultOptions), - localOptions = $.extend(true, clonedDefaults, settings), - $el = $(el); - - localOptions.instances = {}; - $el.data("pwstrength-bootstrap", localOptions); - $el.on("keyup", onKeyUp); - $el.on("change", onKeyUp); - $el.on("paste", onKeyUp); - - ui.initUI(localOptions, $el); - if ($.trim($el.val())) { // Not empty, calculate the strength - $el.trigger("keyup"); - } - - if ($.isFunction(localOptions.common.onLoad)) { - localOptions.common.onLoad(); - } - }); - - return this; - }; - - methods.destroy = function () { - this.each(function (idx, el) { - var $el = $(el), - options = $el.data("pwstrength-bootstrap"), - elements = ui.getUIElements(options, $el); - elements.$progressbar.remove(); - elements.$verdict.remove(); - elements.$errors.remove(); - $el.removeData("pwstrength-bootstrap"); - }); - }; - - methods.forceUpdate = function () { - this.each(function (idx, el) { - var event = { target: el }; - onKeyUp(event); - }); - }; - - methods.addRule = function (name, method, score, active) { - this.each(function (idx, el) { - var options = $(el).data("pwstrength-bootstrap"); - - options.rules.activated[name] = active; - options.rules.scores[name] = score; - options.rules.extra[name] = method; - }); - }; - - applyToAll = function (rule, prop, value) { - this.each(function (idx, el) { - $(el).data("pwstrength-bootstrap").rules[prop][rule] = value; - }); - }; - - methods.changeScore = function (rule, score) { - applyToAll.call(this, rule, "scores", score); - }; - - methods.ruleActive = function (rule, active) { - applyToAll.call(this, rule, "activated", active); - }; - - $.fn.pwstrength = function (method) { - var result; - - if (methods[method]) { - result = methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); - } else if (typeof method === "object" || !method) { - result = methods.init.apply(this, arguments); - } else { - $.error("Method " + method + " does not exist on jQuery.pwstrength-bootstrap"); - } - - return result; - }; - }(jQuery, methods)); -}(jQuery)); \ No newline at end of file + return result; + }; + }(jQuery, methods)); +}(jQuery)); diff --git a/Packages/active-entry/package.js b/Packages/active-entry/package.js index f88ef0cd8..a4e5244fb 100755 --- a/Packages/active-entry/package.js +++ b/Packages/active-entry/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'clinical:active-entry', - version: '1.5.15', + version: '1.5.16', summary: 'SignIn, SignUp, and ForgotPassword pages for Clinical Framework.', git: 'https://github.com/clinical-meteor/clinical-active-entry', documentation: 'README.md' @@ -16,15 +16,13 @@ Package.onUse(function (api) { 'grove:less@0.1.1', 'session', 'reactive-dict', - 'accounts-base', - 'accounts-password', - 'codetheweb:zxcvbn' + //'codetheweb:zxcvbn' ], ['client']); api.use([ 'accounts-base', 'accounts-password' - ], ['server']); + ]); api.use([ 'zuuk:stale-session@1.0.8' @@ -59,6 +57,10 @@ Package.onUse(function (api) { 'components/forgotPassword/forgotPassword.js', 'components/forgotPassword/forgotPassword.less', + 'components/changePassword/changePassword.html', + 'components/changePassword/changePassword.js', + 'components/changePassword/changePassword.less', + ], ['client']); diff --git a/Packages/active-entry/tests/gagarin/activeEntryTests.js b/Packages/active-entry/tests/gagarin/activeEntryTests.js index bbb45d0c7..5ba3a3f13 100644 --- a/Packages/active-entry/tests/gagarin/activeEntryTests.js +++ b/Packages/active-entry/tests/gagarin/activeEntryTests.js @@ -69,13 +69,20 @@ describe('clinical:active-entry', function () { }); // ActiveEntry.verifyConfirmPassword - it('Password match validation confirms that two passwords are the same.', function () { + it('Password match confirms that two passwords are the same.', function () { return client.execute(function (a) { ActiveEntry.verifyConfirmPassword('K1tt#kittens', 'kittens'); expect(ActiveEntry.errorMessages.get('confirm')).to.equal("Passwords do not match"); + ActiveEntry.verifyConfirmPassword('kittens123', 'kittens'); + expect(ActiveEntry.errorMessages.get('confirm')).to.equal("Passwords do not match"); + + ActiveEntry.verifyConfirmPassword('kittens123', 'kittens123'); + expect(ActiveEntry.errorMessages.get('confirm')).to.equal("Passwords match"); + ActiveEntry.verifyConfirmPassword('K1tt#ns123', 'K1tt#ns123'); expect(ActiveEntry.successMessages.get('confirm')).to.equal("Passwords match"); + }); }); @@ -94,13 +101,28 @@ describe('clinical:active-entry', function () { }); + // // ActiveEntry.signIn + // it('Newly created user record should have role, profile, and name set.', function () { + // return client.execute(function () { + // ActiveEntry.signUp('janedoe@test.org', 'Janed*e123', 'Janed*e123', 'Jane Doe'); + // expect(ActiveEntry.successMessages.get('fullName')).to.equal("Name present"); + // }).then(function (){ + // return server.wait(500, 'until account is created on the server', function () { + // return Meteor.users.findOne({'emails.address': 'janedoe@test.org'}); + // }).then(function (user){ + // expect(user.role).to.equal('user'); + // expect(user.profile.fullName).to.equal('Jane Doe'); + // }); + // }); + // }); // ActiveEntry.signIn it('Newly created user record should have role, profile, and name set.', function () { return client.execute(function () { - ActiveEntry.signUp('janedoe@test.org', 'Janed*e123', 'Janed*e123', 'Jane Doe'); + // ActiveEntry.signUp('janedoe@test.org', 'Janed*e123', 'Janed*e123', 'Jane Doe'); + ActiveEntry.signUp('janedoe@test.org', 'Janedoe123', 'Janedoe123', 'Jane Doe'); expect(ActiveEntry.successMessages.get('fullName')).to.equal("Name present"); }).then(function (){ - return server.wait(300, 'until account is created on the server', function () { + return server.wait(500, 'until account is created on the server', function () { return Meteor.users.findOne({'emails.address': 'janedoe@test.org'}); }).then(function (user){ expect(user.role).to.equal('user'); @@ -110,7 +132,6 @@ describe('clinical:active-entry', function () { }); - it("Newly created user should have fullName(), preferredName(), and familyName() methods.", function () { return server.execute(function () { var user = Meteor.users.findOne({'emails.address': 'janedoe@test.org'}); @@ -118,12 +139,12 @@ describe('clinical:active-entry', function () { expect(user.fullName()).to.equal('Jane Doe'); expect(user.givenName()).to.equal('Jane'); expect(user.familyName()).to.equal('Doe'); - }).then(function(){ + }).then(function (){ // client.wait(500, "until user is logged out", function(){ // Meteor.logout(); // }); return client.promise(function (resolve){ - Meteor.logout(function(error, result){ + Meteor.logout(function (error, result){ resolve(); }); }); diff --git a/Packages/active-entry/tests/nightwatch/walkthroughs/activeEntryWalkthrough.js b/Packages/active-entry/tests/nightwatch/walkthroughs/activeEntryWalkthrough.js index 86aa2fe9a..63ae8204c 100755 --- a/Packages/active-entry/tests/nightwatch/walkthroughs/activeEntryWalkthrough.js +++ b/Packages/active-entry/tests/nightwatch/walkthroughs/activeEntryWalkthrough.js @@ -15,6 +15,7 @@ // existing user should be able to sign in on desktop // existing user should be able to sign in on tablet // existing user should be able to sign in on phone +// existing user should be able to change their password // company logo should display on sign//in page @@ -48,7 +49,6 @@ module.exports = { .verify.elementPresent("#signUpPagePasswordInput") .verify.elementPresent("#signUpPageJoinNowButton"); }, - "guest should be notified if password is insecure": function (client) { client .clearValue("input") @@ -158,8 +158,44 @@ module.exports = { .click("#logoutButton").pause(200) .verify.containsText("#usernameLink", "Sign In"); }, - "if anonymous user tries to log in with non-existing account, a message is shown": function ( - client) { + "existing user should be able to change their password" : function (client) { + client + .url("http://localhost:3000/entrySignIn") + .resizeWindow(1600, 1200) + .verify.containsText("#usernameLink", "Sign In") + .signIn("janicedoe@symptomatic.io", "janicedoe123").pause(500) + .verify.containsText("#usernameLink", "janicedoe@symptomatic.io") + .url("http://localhost:3000/changePassword") + .verify.elementPresent("#changePasswordPageOldPasswordInput") + .verify.elementPresent("#changePasswordPagePasswordInput") + .verify.elementPresent("#changePasswordPagePasswordConfirmInput") + .verify.elementPresent("#changePasswordButton") + }, + "existing user should be notified if desired new password is insecure" : function (client) { + client + .url("http://localhost:3000/entrySignIn") + .resizeWindow(1600, 1200) + .verify.containsText("#usernameLink", "Sign In") + .signIn("janicedoe@symptomatic.io", "janicedoe123").pause(500) + .verify.containsText("#usernameLink", "janicedoe@symptomatic.io") + .url("http://localhost:3000/changePassword") + .verify.elementPresent("#changePasswordPageOldPasswordInput") + .verify.elementPresent("#changePasswordPagePasswordInput") + .verify.elementPresent("#changePasswordPagePasswordConfirmInput") + .verify.elementPresent("#changePasswordButton") + .verify.cssProperty('#changePasswordPagePasswordInput', 'border', '1px solid gray') + .setValue("#changePasswordPagePasswordInput", "jan") + .verify.cssProperty('#changePasswordPagePasswordInput', 'border', '1px solid rgb(242, 222, 222)') + .setValue("#changePasswordPagePasswordInput", "icedoe123") + .verify.cssProperty('#changePasswordPagePasswordInput', 'border', '1px solid green') + .verify.cssProperty('#changePasswordPagePasswordConfirmInput', 'border', '1px solid gray') + .setValue("#changePasswordPagePasswordConfirmInput", "ja") + .verify.cssProperty('#changePasswordPagePasswordConfirmInput', 'border', '1px solid rgb(242, 222, 222)') + .clearValue("#changePasswordPagePasswordConfirmInput") + .setValue("#changePasswordPagePasswordConfirmInput", "janicedoe123") + .verify.cssProperty('#changePasswordPagePasswordConfirmInput', 'border', '1px solid green') + }, + "if anonymous user tries to log in with non-existing account, a message is shown" : function (client) { client .url("http://localhost:3000/entrySignIn") .resizeWindow(1024, 768)