diff --git a/Packages/active-entry/components/entrySignUp/entrySignUp.js b/Packages/active-entry/components/entrySignUp/entrySignUp.js
index 463a40825..b9ea40561 100755
--- a/Packages/active-entry/components/entrySignUp/entrySignUp.js
+++ b/Packages/active-entry/components/entrySignUp/entrySignUp.js
@@ -29,6 +29,20 @@ Template.entrySignUp.helpers({
return Session.get('defaultSignInMessage');
}
},
+
+ entryErrorMessages: function () {
+ var errorMessages = [];
+ Object.keys(ActiveEntry.errorMessages.all()).forEach(function(key) {
+ if (key !== "signInError" && ActiveEntry.errorMessages.get(key) &&
+ ActiveEntry.errorMessages.get(key) !== "null" &&
+ ActiveEntry.errorMessages.get(key) !== undefined &&
+ ActiveEntry.errorMessages.get(key) !== null) {
+ errorMessages.push(ActiveEntry.errorMessages.get(key));
+ }
+ });
+ return errorMessages;
+ },
+
getButtonText: function () {
if (ActiveEntry.errorMessages.get('signInError')) {
return ActiveEntry.errorMessages.get('signInError').message;
@@ -41,7 +55,7 @@ Template.entrySignUp.helpers({
return "border: 1px solid #a94442";
} else if (ActiveEntry.errorMessages.equals('email', "Email is poorly formatted")) {
return "border: 1px solid #f2dede";
- } else if (ActiveEntry.errorMessages.equals('email', "Email present")) {
+ } else if (ActiveEntry.successMessages.equals('email', "Email present")) {
return "border: 1px solid green";
} else {
return "border: 1px solid gray";
@@ -50,9 +64,9 @@ Template.entrySignUp.helpers({
getPasswordStyling: function () {
if (ActiveEntry.errorMessages.equals('password', "Password is required")) {
return "border: 1px solid #a94442";
- } else if (ActiveEntry.errorMessages.equals('password', "Password is weak")) {
+ } else if (ActiveEntry.errorMessages.equals('password', "Password is invalid")) {
return "border: 1px solid #f2dede";
- } else if (ActiveEntry.errorMessages.equals('password', "Password present")) {
+ } else if (ActiveEntry.successMessages.equals('password', "Password present")) {
return "border: 1px solid green";
} else {
return "border: 1px solid gray";
@@ -61,9 +75,9 @@ Template.entrySignUp.helpers({
getConfirmPasswordStyling: function () {
if (ActiveEntry.errorMessages.equals('confirm', "Password is required")) {
return "border: 1px solid #a94442";
- } else if (ActiveEntry.errorMessages.equals('confirm', "Password is weak")) {
+ } else if (ActiveEntry.errorMessages.equals('confirm', "Password is invalid")) {
return "border: 1px solid #f2dede";
- } else if (ActiveEntry.errorMessages.equals('confirm', "Passwords match")) {
+ } else if (ActiveEntry.successMessages.equals('confirm', "Passwords match")) {
return "border: 1px solid green";
} else {
return "border: 1px solid gray";
@@ -74,7 +88,7 @@ Template.entrySignUp.helpers({
return "border: 1px solid #a94442";
} else if (ActiveEntry.errorMessages.equals('fullName', "Name is probably not complete")) {
return "border: 1px solid #f2dede";
- } else if (ActiveEntry.errorMessages.equals('fullName', "Name present")) {
+ } else if (ActiveEntry.successMessages.equals('fullName', "Name present")) {
return "border: 1px solid green";
} else {
return "border: 1px solid gray";
@@ -120,7 +134,7 @@ Template.entrySignUp.events({
event.preventDefault();
ActiveEntry.errorMessages.set('signInError', null);
- ActiveEntry.verifyPassword(event, template);
+ //ActiveEntry.verifyPassword(event, template);
var newUser = {
fullName: template.$('[name="fullName"]').val(),
@@ -137,3 +151,8 @@ Template.entrySignUp.events({
);
}
});
+
+Template.entrySignUp.onRendered(function() {
+ // Password strength meter for password inputs
+ this.$(':password').pwstrength(pwstrengthOptions);
+});
diff --git a/Packages/active-entry/components/entrySignUp/entrySignUp.less b/Packages/active-entry/components/entrySignUp/entrySignUp.less
index de57917e4..6c35a257e 100755
--- a/Packages/active-entry/components/entrySignUp/entrySignUp.less
+++ b/Packages/active-entry/components/entrySignUp/entrySignUp.less
@@ -5,3 +5,7 @@
color: black;
}
}
+
+.progress {
+ height: 5px;
+}
diff --git a/Packages/active-entry/lib/ActiveEntry.js b/Packages/active-entry/lib/ActiveEntry.js
index cc0e897fb..a77cf890f 100755
--- a/Packages/active-entry/lib/ActiveEntry.js
+++ b/Packages/active-entry/lib/ActiveEntry.js
@@ -31,6 +31,9 @@ if (Meteor.isClient) {
ActiveEntry.errorMessages = new ReactiveDict('errorMessages');
ActiveEntry.errorMessages.set('signInError', false);
+ // Success messages
+ ActiveEntry.successMessages = new ReactiveDict('successMessages');
+
}
@@ -46,39 +49,48 @@ ActiveEntry.configure = function (configObject) {
ActiveEntry.verifyPassword = function (password) {
if (password.length === 0) {
ActiveEntry.errorMessages.set('password', 'Password is required');
- } else if (password.length < 8) {
- ActiveEntry.errorMessages.set('password', 'Password is weak');
- } else if (password.length >= 8) {
- ActiveEntry.errorMessages.set('password', 'Password present');
- }
-};
-ActiveEntry.verifyConfirmPassword = function (password, confirmPassword) {
- if (confirmPassword.length === 0) {
- ActiveEntry.errorMessages.set('confirm', 'Password is required');
- } else if (confirmPassword.length < 8) {
- ActiveEntry.errorMessages.set('confirm', 'Password is weak');
+ ActiveEntry.successMessages.set('password', null);
+ } else if (!validatePassword(password)) {
+ ActiveEntry.errorMessages.set('password', 'Password is invalid');
+ ActiveEntry.successMessages.set('password', null);
+ } else {
+ //ActiveEntry.errorMessages.set('password', 'Password present');
+ ActiveEntry.errorMessages.set('password', null);
+ ActiveEntry.successMessages.set('password', 'Password present');
}
+};
+ActiveEntry.verifyConfirmPassword = function (password, confirmPassword) {
if (confirmPassword === password) {
- ActiveEntry.errorMessages.set('confirm', 'Passwords match');
+ //ActiveEntry.errorMessages.set('confirm', 'Passwords match');
+ ActiveEntry.errorMessages.set('confirm', null);
+ ActiveEntry.successMessages.set('confirm', 'Passwords match');
}
};
ActiveEntry.verifyEmail = function (email) {
if (email.length === 0) {
ActiveEntry.errorMessages.set('email', 'Email is required');
+ ActiveEntry.successMessages.set('email', null);
} else if (email.indexOf("@") === -1){
ActiveEntry.errorMessages.set('email', 'Email is poorly formatted');
+ ActiveEntry.successMessages.set('email', null);
} else if (email.indexOf("@") >= 0){
- ActiveEntry.errorMessages.set('email', 'Email present');
+ //ActiveEntry.errorMessages.set('email', 'Email present');
+ ActiveEntry.errorMessages.set('email', null);
+ ActiveEntry.successMessages.set('email', 'Email present');
}
};
ActiveEntry.verifyFullName = function (fullName) {
if (fullName.length === 0) {
ActiveEntry.errorMessages.set('fullName', 'Name is required');
+ ActiveEntry.successMessages.set('fullName', null);
} else if (fullName.indexOf(" ") === -1){
ActiveEntry.errorMessages.set('fullName', 'Name is probably not complete');
+ ActiveEntry.successMessages.set('fullName', null);
} else if (fullName.indexOf(" ") >= 0){
- ActiveEntry.errorMessages.set('fullName', 'Name present');
+ //ActiveEntry.errorMessages.set('fullName', 'Name present');
+ ActiveEntry.errorMessages.set('fullName', null);
+ ActiveEntry.successMessages.set('fullName', 'Name present');
}
};
@@ -104,6 +116,18 @@ ActiveEntry.signUp = function (emailValue, passwordValue, confirmPassword, fullN
ActiveEntry.verifyConfirmPassword(passwordValue, confirmPassword);
ActiveEntry.verifyFullName(fullName);
+ var errorIsFound = false;
+ Object.keys(ActiveEntry.errorMessages.keys).forEach(function(key) {
+ if (ActiveEntry.errorMessages.get(key) !== "null" && ActiveEntry.errorMessages.get(key) !== null) {
+ errorIsFound = true;
+ }
+ });
+
+ if(errorIsFound) {
+ // TODO: Show error messages
+ return;
+ }
+
Accounts.createUser({
email: emailValue,
password: passwordValue,
diff --git a/Packages/active-entry/lib/jquery.pwstrength.bootstrap.js b/Packages/active-entry/lib/jquery.pwstrength.bootstrap.js
new file mode 100644
index 000000000..ce466d7fe
--- /dev/null
+++ b/Packages/active-entry/lib/jquery.pwstrength.bootstrap.js
@@ -0,0 +1,708 @@
+/*!
+ * jQuery Password Strength plugin for Twitter Bootstrap
+ *
+ * Copyright (c) 2008-2013 Tane Piper
+ * Copyright (c) 2013 Alejandro Blanco
+ * Dual licensed under the MIT and GPL licenses.
+ */
+
+(function (jQuery) {
+// Source: src/rules.js
+
+
+
+
+ var rulesEngine = {};
+
+ 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 = {};
+
+ 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;
+ }
+ 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;
+ }
+ } catch (ignore) {}
+
+// Source: src/options.js
+
+
+
+
+ var defaultOptions = {};
+
+ 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 = [
+ // List of disrecommended words
+ ];
+ 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.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:
";
+
+ jQuery.each(errors, function (idx, err) {
+ message += "- " + err + "
";
+ });
+ message += "
";
+ 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"
+ };
+ 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
+ };
+ 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;
+ };
+
+ ui.findElement = function ($container, viewport, cssSelector) {
+ if (viewport) {
+ return $container.find(viewport).find(cssSelector);
+ }
+ return $container.find(cssSelector);
+ };
+
+ ui.getUIElements = function (options, $el) {
+ var $container, selector, result;
+
+ if (options.instances.viewports) {
+ return options.instances.viewports;
+ }
+
+ $container = ui.getContainer(options, $el);
+
+ 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");
+ }
+
+ 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");
+ }
+
+ options.instances.viewports = result;
+ return result;
+ };
+
+ ui.initProgressBar = function (options, $el) {
+ var $container = ui.getContainer(options, $el),
+ progressbar = "
";
+ if (options.ui.bootstrap4) {
+ // Boostrap 4
+ 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
diff --git a/Packages/active-entry/lib/validatePassword.js b/Packages/active-entry/lib/validatePassword.js
new file mode 100644
index 000000000..a6594a188
--- /dev/null
+++ b/Packages/active-entry/lib/validatePassword.js
@@ -0,0 +1,19 @@
+pwstrengthOptions = {
+ common: {
+ minChar: 8,
+ zxcvbn: true
+ },
+ ui: {
+ showVerdictsInsideProgressBar: true,
+ showStatus: true
+ }
+};
+
+// Validate Password: at least 8 characters in length and contain at least 1 uppercase, 1 lowercase and 1 number and 1 special character
+validatePassword = function(password) {
+ var result = password.search(/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&*])[0-9a-zA-Z!@#$%^&*]{8,}$/i);
+ if (result > -1) {
+ return true;
+ }
+ return false;
+};
\ No newline at end of file
diff --git a/Packages/active-entry/package.js b/Packages/active-entry/package.js
index df73cd9ad..3f1129c79 100755
--- a/Packages/active-entry/package.js
+++ b/Packages/active-entry/package.js
@@ -17,7 +17,8 @@ Package.onUse(function (api) {
'session',
'reactive-dict',
'accounts-base',
- 'accounts-password'
+ 'accounts-password',
+ 'codetheweb:zxcvbn'
], ['client']);
api.use([
@@ -25,11 +26,20 @@ Package.onUse(function (api) {
'accounts-password'
], ['server']);
+ api.use([
+ 'zuuk:stale-session@1.0.8'
+ ], ['client', 'server']);
+
api.addFiles([
'lib/ActiveEntry.js',
'lib/Accounts.js'
]);
+ api.addFiles([
+ 'lib/jquery.pwstrength.bootstrap.js',
+ 'lib/validatePassword.js'
+ ], ['client']);
+
api.imply('accounts-base');
api.imply('accounts-password');
diff --git a/Packages/active-entry/tests/gagarin/activeEntryTests.js b/Packages/active-entry/tests/gagarin/activeEntryTests.js
index f93225997..84ff7e484 100644
--- a/Packages/active-entry/tests/gagarin/activeEntryTests.js
+++ b/Packages/active-entry/tests/gagarin/activeEntryTests.js
@@ -43,7 +43,7 @@ describe('clinical:active-entry', function () {
it('Email validation confirms it is a properly formatted email.', function () {
return client.execute(function (a) {
ActiveEntry.verifyEmail('janedoe@somewhere.com');
- expect(ActiveEntry.errorMessages.get('email')).to.equal("Email present");
+ expect(ActiveEntry.successMessages.get('email')).to.equal("Email present");
ActiveEntry.verifyEmail('');
expect(ActiveEntry.errorMessages.get('email')).to.equal("Email is required");
@@ -61,24 +61,18 @@ describe('clinical:active-entry', function () {
expect(ActiveEntry.errorMessages.get('password')).to.equal("Password is required");
ActiveEntry.verifyPassword('kittens');
- expect(ActiveEntry.errorMessages.get('password')).to.equal("Password is weak");
+ expect(ActiveEntry.errorMessages.get('password')).to.equal("Password is invalid");
- ActiveEntry.verifyPassword('kittens123');
- expect(ActiveEntry.errorMessages.get('password')).to.equal("Password present");
+ ActiveEntry.verifyPassword('K1tt#ns123');
+ expect(ActiveEntry.successMessages.get('password')).to.equal("Password present");
});
});
// ActiveEntry.verifyConfirmPassword
it('Password match validation confirms that two passwords are the same.', function () {
return client.execute(function (a) {
- ActiveEntry.verifyConfirmPassword('kittens123', '');
- expect(ActiveEntry.errorMessages.get('confirm')).to.equal("Password is required");
-
- ActiveEntry.verifyConfirmPassword('kittens123', 'kittens');
- expect(ActiveEntry.errorMessages.get('confirm')).to.equal("Password is weak");
-
- 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");
});
});
@@ -92,7 +86,7 @@ describe('clinical:active-entry', function () {
expect(ActiveEntry.errorMessages.get('fullName')).to.equal("Name is probably not complete");
ActiveEntry.verifyFullName('Jane Doe');
- expect(ActiveEntry.errorMessages.get('fullName')).to.equal("Name present");
+ expect(ActiveEntry.successMessages.get('fullName')).to.equal("Name present");
});
});
diff --git a/Packages/active-entry/tests/nightwatch/walkthroughs/activeEntryWalkthrough.js b/Packages/active-entry/tests/nightwatch/walkthroughs/activeEntryWalkthrough.js
index b3b6ff046..936a9cbd6 100755
--- a/Packages/active-entry/tests/nightwatch/walkthroughs/activeEntryWalkthrough.js
+++ b/Packages/active-entry/tests/nightwatch/walkthroughs/activeEntryWalkthrough.js
@@ -45,7 +45,7 @@ module.exports = {
"user should be able to request be able to create new account" : function (client) {
client.verify.elementPresent("#signUpPageEmailInput")
.verify.elementPresent("#signUpPagePasswordInput")
- .verify.elementPresent("#signUpPagePasswordInput")
+ .verify.elementPresent("#signUpPagePasswordConfirmInput")
.verify.elementPresent("#signUpPageJoinNowButton")
},
@@ -56,14 +56,14 @@ module.exports = {
.verify.cssProperty('#signUpPagePasswordInput', 'border', '1px solid gray')
.setValue("#signUpPagePasswordInput", "jan")
.verify.cssProperty('#signUpPagePasswordInput', 'border', '1px solid rgb(242, 222, 222)')
- .setValue("#signUpPagePasswordInput", "icedoe123")
+ .setValue("#signUpPagePasswordInput", "iceD*e123")
.verify.cssProperty('#signUpPagePasswordInput', 'border', '1px solid green')
.verify.cssProperty('#signUpPagePasswordConfirmInput', 'border', '1px solid gray')
.setValue("#signUpPagePasswordConfirmInput", "ja")
.verify.cssProperty('#signUpPagePasswordConfirmInput', 'border', '1px solid rgb(242, 222, 222)')
.clearValue("#signUpPagePasswordConfirmInput")
- .setValue("#signUpPagePasswordConfirmInput", "janicedoe123")
+ .setValue("#signUpPagePasswordConfirmInput", "Janiced*e123")
.verify.cssProperty('#signUpPagePasswordConfirmInput', 'border', '1px solid green')
},
"guest should be notified if passwords do not match" : function (client) {
@@ -74,10 +74,10 @@ module.exports = {
.pause(500)
.verify.cssProperty('#signUpPagePasswordInput', 'border', '1px solid gray')
.verify.cssProperty('#signUpPagePasswordConfirmInput', 'border', '1px solid gray')
- .setValue("#signUpPagePasswordInput", "janicedoe123")
+ .setValue("#signUpPagePasswordInput", "Janiced*e123")
.verify.cssProperty('#signUpPagePasswordInput', 'border', '1px solid green')
.verify.cssProperty('#signUpPagePasswordConfirmInput', 'border', '1px solid gray')
- .setValue("#signUpPagePasswordConfirmInput", "janicedoe123")
+ .setValue("#signUpPagePasswordConfirmInput", "Janiced*e123")
.verify.cssProperty('#signUpPagePasswordInput', 'border', '1px solid green')
.verify.cssProperty('#signUpPagePasswordConfirmInput', 'border', '1px solid green')
},
@@ -104,8 +104,8 @@ module.exports = {
.setValue("#signUpPageFullNameInput", "Janice Doe")
.setValue("#signUpPageEmailInput", "janicedoe@symptomatic.io")
- .setValue("#signUpPagePasswordInput", "janicedoe123")
- .setValue("#signUpPagePasswordConfirmInput", "janicedoe123")
+ .setValue("#signUpPagePasswordInput", "Janiced*e123")
+ .setValue("#signUpPagePasswordConfirmInput", "Janiced*e123")
.click("#signUpPageJoinNowButton").pause(1000)
@@ -131,7 +131,7 @@ module.exports = {
.url("http://localhost:3000/entrySignIn")
.resizeWindow(1600, 1200)
.verify.containsText("#usernameLink", "Sign In")
- .signIn("janicedoe@symptomatic.io", "janicedoe123").pause(500)
+ .signIn("janicedoe@symptomatic.io", "Janiced*e123").pause(500)
.verify.containsText("#usernameLink", "janicedoe@symptomatic.io")
.click("#logoutButton").pause(200)
.verify.containsText("#usernameLink", "Sign In")
@@ -141,7 +141,7 @@ module.exports = {
.url("http://localhost:3000/entrySignIn")
.resizeWindow(1024, 768)
.verify.containsText("#usernameLink", "Sign In")
- .signIn("janicedoe@symptomatic.io", "janicedoe123").pause(500)
+ .signIn("janicedoe@symptomatic.io", "Janiced*e123").pause(500)
.verify.containsText("#usernameLink", "janicedoe@symptomatic.io")
.click("#logoutButton").pause(200)
.verify.containsText("#usernameLink", "Sign In")
@@ -151,7 +151,7 @@ module.exports = {
.url("http://localhost:3000/entrySignIn")
.resizeWindow(320, 960)
// .verify.containsText("#usernameLink", "Sign In")
- .signIn("janicedoe@symptomatic.io", "janicedoe123").pause(500)
+ .signIn("janicedoe@symptomatic.io", "Janiced*e123").pause(500)
.click("#sidebarToggle").pause(300)
.verify.containsText("#usernameLink", "janicedoe@symptomatic.io")
.click("#logoutButton").pause(200)
@@ -171,7 +171,7 @@ module.exports = {
client
.url("http://localhost:3000/entrySignUp")
.resizeWindow(1024, 768)
- .signUp("janicedoe@symptomatic.io", "janicedoe123").pause(500)
+ .signUp("janicedoe@symptomatic.io", "Janiced*e123").pause(500)
.click("#signUpPageEmailInput").pause(500)
.verify.elementPresent("#signUpPageMessage")
.verify.containsText("#signUpPageMessage", "Email already exists. [403]")
diff --git a/config/localhostOrthanc.json b/config/localhostOrthanc.json
index 0097b2f56..8535b2975 100644
--- a/config/localhostOrthanc.json
+++ b/config/localhostOrthanc.json
@@ -17,5 +17,11 @@
}
}
]
+ },
+ "public": {
+ "staleSessionInactivityTimeout": 1800000,
+ "staleSessionHeartbeatInterval": 180000,
+ "staleSessionPurgeInterval": 60000,
+ "staleSessionActivityEvents": "mousemove click keydown"
}
}
diff --git a/config/medicalConnections.json b/config/medicalConnections.json
index faf254197..fd35535ec 100644
--- a/config/medicalConnections.json
+++ b/config/medicalConnections.json
@@ -15,5 +15,11 @@
}
}
]
+ },
+ "public": {
+ "staleSessionInactivityTimeout": 1800000,
+ "staleSessionHeartbeatInterval": 180000,
+ "staleSessionPurgeInterval": 60000,
+ "staleSessionActivityEvents": "mousemove click keydown"
}
}
\ No newline at end of file
diff --git a/config/medkenOrthanc.json b/config/medkenOrthanc.json
index 8c142d90b..21996628a 100644
--- a/config/medkenOrthanc.json
+++ b/config/medkenOrthanc.json
@@ -16,5 +16,11 @@
}
}
]
+ },
+ "public": {
+ "staleSessionInactivityTimeout": 1800000,
+ "staleSessionHeartbeatInterval": 180000,
+ "staleSessionPurgeInterval": 60000,
+ "staleSessionActivityEvents": "mousemove click keydown"
}
}
\ No newline at end of file
diff --git a/config/siimDCM4CHEE.json b/config/siimDCM4CHEE.json
index 30408e8f8..d8f1253ef 100644
--- a/config/siimDCM4CHEE.json
+++ b/config/siimDCM4CHEE.json
@@ -15,5 +15,11 @@
}
}
]
+ },
+ "public": {
+ "staleSessionInactivityTimeout": 1800000,
+ "staleSessionHeartbeatInterval": 180000,
+ "staleSessionPurgeInterval": 60000,
+ "staleSessionActivityEvents": "mousemove click keydown"
}
}
\ No newline at end of file