UNPKG

password-meter

Version:

This password meter library is inspired by pointing system in http://www.passwordmeter.com/, in which the main purpose is to help the end users to have more stronger passwords.

807 lines (803 loc) 29.7 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var PasswordMeter = /** @class */ (function () { function PasswordMeter(requirements, scoreRange) { this.requirements = requirements; this.scoreRange = scoreRange; this.uppercaseLetters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; this.lowercaseLetters = 'abcdefghijklmnopqrstuvwxyz'; this.numbers = '1234567890'; } PasswordMeter.prototype.startsWith = function (str, word) { return str.lastIndexOf(word, 0) === 0; }; PasswordMeter.prototype.endsWith = function (str, word) { return str.indexOf(word, str.length - word.length) !== -1; }; PasswordMeter.prototype.chunkString = function (str, len) { var _size = Math.ceil(str.length / len), _ret = new Array(_size); var _offset = 0; for (var _i = 0; _i < _size; _i++) { _offset = _i * len; _ret[_i] = str.substring(_offset, _offset + len); } return _ret; }; PasswordMeter.prototype.getLength = function (text) { if (text) { return text.length; } return 0; }; PasswordMeter.prototype.doesNotContains = function (text, list) { if (text) { if (list) { var doesnotContainsAll = list.every(function (x) { return text.indexOf(x) == -1; }); return doesnotContainsAll; } else { return true; } } else { return true; } }; PasswordMeter.prototype.contains = function (text, list) { if (text) { if (list) { var containsAll = list.every(function (x) { return text.indexOf(x) >= 0; }); return containsAll; } else { return false; } } else { return false; } }; PasswordMeter.prototype.containsOne = function (text, list) { if (text) { if (list) { var contains = list.some(function (x) { return text.indexOf(x) >= 0; }); return contains; } else { return false; } } else { return false; } }; PasswordMeter.prototype.isInBlackList = function (text, list) { if (text) { if (list) { for (var index = 0; index < list.length; index++) { if (text === list[index]) { return true; } } return false; } else { return false; } } else { return false; } }; PasswordMeter.prototype.between = function (x, min, max) { return x >= min && x < max; }; PasswordMeter.prototype.isIMessage = function (arg) { var status = arg.message !== undefined; return status; }; PasswordMeter.prototype.isNumber = function (text) { if (text) { var pattern = /^\d+$/; return pattern.test(text); } return false; }; PasswordMeter.prototype.isLetter = function (text) { if (text) { var pattern = /^[a-zA-Z]+$/; return pattern.test(text); } return false; }; PasswordMeter.prototype.isUppercaseLetter = function (text) { if (text) { var pattern = /^[A-Z]+$/; return pattern.test(text); } return false; }; PasswordMeter.prototype.isLowercaseLetter = function (text) { if (text) { var pattern = /^[a-z]+$/; return pattern.test(text); } return false; }; PasswordMeter.prototype.isSymbol = function (text) { if (text) { return !this.isNumber(text) && !this.isLetter(text); } return false; }; PasswordMeter.prototype.getSymbols = function (text) { var result = ''; if (text) { for (var index = 0; index < text.length; index++) { if (this.isSymbol(text[index])) result += text[index]; } } if (result.length === 0) return undefined; return result; }; PasswordMeter.prototype.getLengthScore = function (text) { if (text) { // +(n*9) var ratio = 9; return this.getLength(text) * ratio; } return 0; }; PasswordMeter.prototype.getUppercaseLettersScore = function (text) { var _this = this; if (text) { // +((len-n)*2) var ratio = 2; var n_1 = 0; text.split('').forEach(function (value) { if (_this.isUppercaseLetter(value)) { n_1++; } }); if (n_1 == 0) { return 0; } return (this.getLength(text) - n_1) * ratio; } return 0; }; PasswordMeter.prototype.getLowercaseLettersScore = function (text) { var _this = this; if (text) { // +((len-n)*2) var ratio = 2; var n_2 = 0; text.split('').forEach(function (value) { if (_this.isLowercaseLetter(value)) { n_2++; } }); if (n_2 == 0) { return 0; } return (this.getLength(text) - n_2) * ratio; } return 0; }; PasswordMeter.prototype.getNumbersScore = function (text) { var _this = this; if (text) { // +((len-n)*4) var ratio = 4; var n_3 = 0; text.split('').forEach(function (value) { if (_this.isNumber(value)) { n_3++; } }); if (n_3 == 0) { return 0; } return (this.getLength(text) - n_3) * ratio; } return 0; }; PasswordMeter.prototype.getSymbolsScore = function (text) { var _this = this; if (text) { // +((len-n)*6) var ratio = 6; var n_4 = 0; text.split('').forEach(function (value) { if (_this.isSymbol(value)) { n_4++; } }); if (n_4 == 0) { return 0; } return (this.getLength(text) - n_4) * ratio; } return 0; }; PasswordMeter.prototype.getLettersOnlyScore = function (text) { if (text) { // -n var ratio = -1; if (this.isLetter(text)) { return this.getLength(text) * ratio; } } return 0; }; PasswordMeter.prototype.getNumbersOnlyScore = function (text) { if (text) { // -n var ratio = -1; if (this.isNumber(text)) { return this.getLength(text) * ratio; } } return 0; }; PasswordMeter.prototype.getConsecutiveUppercaseLettersScore = function (text) { var _this = this; if (text) { var pattern = /[A-Z]+/g; var results = text.match(pattern); if (!results) { return 0; } var score_1 = 0; var ratio_1 = -2; results.forEach(function (value) { if (_this.getLength(value) > 1) { // -(n*2) score_1 += (_this.getLength(value) - 1) * /*There is no problem with a character, but the remaining repetition creates the problem.*/ ratio_1; } }); return score_1; } return 0; }; PasswordMeter.prototype.getConsecutiveLowercaseLettersScore = function (text) { var _this = this; if (text) { var pattern = /[a-z]+/g; var results = text.match(pattern); if (!results) { return 0; } var score_2 = 0; var ratio_2 = -2; results.forEach(function (value) { if (_this.getLength(value) > 1) { // -(n*2) score_2 += (_this.getLength(value) - 1) * /*There is no problem with a character, but the remaining repetition creates the problem.*/ ratio_2; } }); return score_2; } return 0; }; PasswordMeter.prototype.getConsecutiveNumbersScore = function (text) { var _this = this; if (text) { var pattern = /[0-9]+/g; var results = text.match(pattern); if (!results) { return 0; } var score_3 = 0; var ratio_3 = -2; results.forEach(function (value) { if (_this.getLength(value) > 1) { // -(n*2) score_3 += (_this.getLength(value) - 1) * /*There is no problem with a character, but the remaining repetition creates the problem.*/ ratio_3; } }); return score_3; } return 0; }; PasswordMeter.prototype.reverseString = function (str) { return str.split('').reverse().join(''); }; PasswordMeter.prototype.sequentialBuilder = function (text, minChunk) { if (text) { var list = []; var len = text.split('').length - minChunk; for (var i = 0; i < len; i++) { for (var index = 0; index < len; index++) { var newText = text.substring(index, text.length); var arr = this.chunkString(newText, i + minChunk); for (var j = 0; j < arr.length; j++) { list.push(arr[j]); list.push(this.reverseString(arr[j])); } } } var result = this.distinctArray(this.sortByLength(list, minChunk)); return result; } return []; }; PasswordMeter.prototype.distinctArray = function (arr) { var a = []; for (var i = 0, l = arr.length; i < l; i++) if (a.indexOf(arr[i]) === -1 && arr[i] !== '') a.push(arr[i]); return a; }; PasswordMeter.prototype.sortByLength = function (arr, limit) { arr.sort(function (a, b) { return b.length - a.length; }); var list = []; for (var index = 0; index < arr.length; index++) { if (limit) { if (arr[index].length >= limit) { list.push(arr[index]); } } else { list.push(arr[index]); } } return list; }; PasswordMeter.prototype.getSequentialLettersScore = function (text) { var minChunk = 3; if (text) { var uStr = this.sequentialBuilder(this.uppercaseLetters, minChunk); var lStr = this.sequentialBuilder(this.lowercaseLetters, minChunk); var score_4 = 0; var uTxt_1 = text; var lTxt_1 = text; uStr.forEach(function (value) { if (uTxt_1.indexOf(value) != -1) { score_4 += value.length - (minChunk - 1); uTxt_1 = uTxt_1.replace(value, ''); } }); lStr.forEach(function (value) { if (lTxt_1.indexOf(value) != -1) { score_4 += value.length - (minChunk - 1); lTxt_1 = lTxt_1.replace(value, ''); } }); // -(n*3) var ratio = -3; return score_4 * ratio; } return 0; }; PasswordMeter.prototype.getSequentialNumbersScore = function (text) { var minChunk = 3; if (text) { var num = this.sequentialBuilder(this.numbers, minChunk); var score_5 = 0; var txt_1 = text; num.forEach(function (value) { if (txt_1.indexOf(value) != -1) { score_5 += value.length - (minChunk - 1); txt_1 = txt_1.replace(value, ''); } }); // -(n*3) var ratio = -3; return score_5 * ratio; } return 0; }; PasswordMeter.prototype.getSequentialSymbolsScore = function (text) { var minChunk = 3; var sym = this.getSymbols(text); if (text && sym) { var num = this.sequentialBuilder(sym, minChunk); var score_6 = 0; var txt_2 = text; num.forEach(function (value) { if (txt_2.indexOf(value) != -1) { score_6 += value.length - (minChunk - 1); txt_2 = txt_2.replace(value, ''); } }); // -(n*3) var ratio = -3; return score_6 * ratio; } return 0; }; PasswordMeter.prototype.getRepeatCharactersScore = function (text) { var pattern = /(.+)(?=.*?\1)/g; if (text) { var matches = text.match(pattern); if (!matches) { return 0; } var maxResultLength = this.sortByLength(matches)[0].length; var ratio = 0; if (maxResultLength >= 1 && maxResultLength <= 5) ratio = -8; if (maxResultLength >= 6 && maxResultLength <= 10) ratio = -5; if (maxResultLength >= 11) ratio = -2; // (-X * maxRegexResultLength) + (textLength - (maxRegexResultLength *2)) var score = ratio * maxResultLength + (text.length - maxResultLength * 2); return score; } return 0; }; PasswordMeter.prototype.getRequirementsScore = function (text, ignoreCase) { var req = this.requirements; var errors = []; if (req) { var minLengthMsg = 'The minimum password length is ' + req.minLength + '.'; var maxLengthMsg = 'The maximum password length is ' + req.maxLength + '.'; var uppercaseLettersMinLengthMsg = 'You must use at least ' + req.uppercaseLettersMinLength + ' uppercase letter(s).'; var lowercaseLettersMinLengthMsg = 'You must use at least ' + req.lowercaseLettersMinLength + ' lowercase letter(s).'; var numbersMinLengthMsg = 'You must use at least ' + req.numbersMinLength + ' number(s).'; var symbolsMinLengthMsg = 'You must use at least ' + req.symbolsMinLength + ' symbol(s).'; var includeMsg = 'The Password must include all the items specified.'; var excludeMsg = 'The Password must exclude all the items specified.'; var startsWithMsg = 'The password must start with ' + req.startsWith + '.'; var endsWithMsg = 'The password must end with ' + req.endsWith + '.'; var blackListMsg = 'Your password is in the blacklist.'; var includeOneMsg = 'The Password must include at least one item specified [' + req.includeOne + '] .'; var uniqueLettersMinLength = 'You must use at least ' + req.uniqueLettersMinLength + ' unique letter(s).'; var upperCount = (text.match(/[A-Z]/g) || []).length; var lowerCount = (text.match(/[a-z]/g) || []).length; var numbersCount = (text.match(/[0-9]/g) || []).length; var symbolsCount = text.length - (upperCount + lowerCount + numbersCount); if (req.minLength) { var val = void 0; var msg = minLengthMsg; if (this.isIMessage(req.minLength)) { val = req.minLength.value; msg = req.minLength.message; } else { val = req.minLength; } if (req.minLength && text.length < val) { errors.push(msg); } } if (req.maxLength) { var val = void 0; var msg = maxLengthMsg; if (this.isIMessage(req.maxLength)) { val = req.maxLength.value; msg = req.maxLength.message; } else { val = req.maxLength; } if (req.maxLength && text.length > val) { errors.push(msg); } } if (req.startsWith) { var val = void 0; var msg = startsWithMsg; if (this.isIMessage(req.startsWith)) { val = req.startsWith.value; msg = req.startsWith.message; } else { val = req.startsWith; } if (!this.startsWith(text, val)) { errors.push(msg); } } if (req.endsWith) { var val = void 0; var msg = endsWithMsg; if (this.isIMessage(req.endsWith)) { val = req.endsWith.value; msg = req.endsWith.message; } else { val = req.endsWith; } if (!this.endsWith(text, val)) { errors.push(msg); } } if (req.uppercaseLettersMinLength) { var val = void 0; var msg = uppercaseLettersMinLengthMsg; if (this.isIMessage(req.uppercaseLettersMinLength)) { val = req.uppercaseLettersMinLength.value; msg = req.uppercaseLettersMinLength.message; } else { val = req.uppercaseLettersMinLength; } if (val > upperCount) { errors.push(msg); } } if (req.lowercaseLettersMinLength) { var val = void 0; var msg = lowercaseLettersMinLengthMsg; if (this.isIMessage(req.lowercaseLettersMinLength)) { val = req.lowercaseLettersMinLength.value; msg = req.lowercaseLettersMinLength.message; } else { val = req.lowercaseLettersMinLength; } if (val > lowerCount) { errors.push(msg); } } if (req.numbersMinLength) { var val = void 0; var msg = numbersMinLengthMsg; if (this.isIMessage(req.numbersMinLength)) { val = req.numbersMinLength.value; msg = req.numbersMinLength.message; } else { val = req.numbersMinLength; } if (val > numbersCount) { errors.push(msg); } } if (req.symbolsMinLength) { var val = void 0; var msg = symbolsMinLengthMsg; if (this.isIMessage(req.symbolsMinLength)) { val = req.symbolsMinLength.value; msg = req.symbolsMinLength.message; } else { val = req.symbolsMinLength; } if (val > symbolsCount) { errors.push(msg); } } if (req.uniqueLettersMinLength) { var val = void 0; var msg = uniqueLettersMinLength; if (this.isIMessage(req.uniqueLettersMinLength)) { val = req.uniqueLettersMinLength.value; msg = req.uniqueLettersMinLength.message; } else { val = req.uniqueLettersMinLength; } var isValid = Array.from(new Set(text.split(''))).length >= val; if (req.uniqueLettersMinLength && !isValid) { errors.push(msg); } } if (req.include) { var val = void 0; var msg = includeMsg; if (this.isIMessage(req.include)) { val = req.include.value; msg = req.include.message; } else { val = req.include; } if (!this.contains(text, val)) { errors.push(msg); } } if (req.exclude) { var txt = text; var val = void 0; var msg = excludeMsg; if (this.isIMessage(req.exclude)) { val = req.exclude.value; msg = req.exclude.message; } else { val = req.exclude; } if (ignoreCase) { txt = text.toLowerCase(); val = val.map(function (v) { return v.toLowerCase(); }); } if (!this.doesNotContains(txt, val)) { errors.push(msg); } } if (req.blackList) { var txt = text; var val = void 0; var msg = blackListMsg; if (this.isIMessage(req.blackList)) { val = req.blackList.value; msg = req.blackList.message; } else { val = req.blackList; } if (ignoreCase) { txt = text.toLowerCase(); val = val.map(function (v) { return v.toLowerCase(); }); } if (this.isInBlackList(txt, val)) { errors.push(msg); } } if (req.includeOne) { var txt = text; var val = void 0; var msg = includeOneMsg; if (this.isIMessage(req.includeOne)) { val = req.includeOne.value; msg = req.includeOne.message; } else { val = req.includeOne; } if (ignoreCase) { txt = text.toLowerCase(); val = val.map(function (v) { return v.toLowerCase(); }); } if (!this.containsOne(txt, val)) { errors.push(msg); } } return errors; } return []; }; PasswordMeter.prototype.getResults = function (passwords, ignoreCase, skipReq) { if (ignoreCase === void 0) { ignoreCase = false; } if (skipReq === void 0) { skipReq = false; } var results = []; if (passwords && passwords.length > 0) { for (var index = 0; index < passwords.length; index++) { results.push(this.getResult(passwords[index], ignoreCase, skipReq)); } return results; } return []; }; PasswordMeter.prototype.getResult = function (password, ignoreCase, skipReq) { if (ignoreCase === void 0) { ignoreCase = false; } if (skipReq === void 0) { skipReq = false; } if (password) { // Requirements var req = this.getRequirementsScore(password, ignoreCase); if (!skipReq && req.length) { return { score: -1, status: 'needs requirement(s)', errors: req, percent: 0, }; } // Additions var len = this.getLengthScore(password); var upper = this.getUppercaseLettersScore(password); var lower = this.getLowercaseLettersScore(password); var num = this.getNumbersScore(password); var symbol = this.getSymbolsScore(password); // Deductions var letterOnly = this.getLettersOnlyScore(password); var numberOnly = this.getNumbersOnlyScore(password); var repetition = this.getRepeatCharactersScore(password); var consecutiveUpper = this.getConsecutiveUppercaseLettersScore(password); var consecutiveLower = this.getConsecutiveLowercaseLettersScore(password); var consecutiveNumber = this.getConsecutiveNumbersScore(password); var seqLetters = this.getSequentialLettersScore(password); var seqNumbers = this.getSequentialNumbersScore(password); var seqSymbols = this.getSequentialSymbolsScore(password); var score = len + upper + lower + num + symbol + letterOnly + numberOnly + repetition + consecutiveUpper + consecutiveLower + consecutiveNumber + seqLetters + seqNumbers + seqSymbols; var defaultRanges = { '40': 'veryWeak', '80': 'weak', '120': 'medium', '180': 'strong', '200': 'veryStrong', _: 'perfect', // >= 200 }; var stat = ''; if (!this.scoreRange) { this.scoreRange = defaultRanges; } var range = Object.keys(this.scoreRange).sort(function (a, b) { if (isNaN(a) || isNaN(b)) { if (a > b) return 1; else return -1; } return a - b; }); if (range.length < 2) { return { score: -2, status: 'error', errors: '"scoreRange" must have at least two members.', percent: 0, }; } for (var index = 0; index < range.length; index++) { var key = range[index]; if (key != undefined) { if (index == 0) { if (this.between(score, 1, parseFloat(range[index]))) { stat = this.scoreRange[range[0]]; break; } } if (index === range.length - 1) { if (range[index] == '_') { if (this.between(score, parseFloat(range[index - 1]), 1000000000000000000)) { stat = this.scoreRange[range[range.length - 1]]; break; } } else { return { score: -2, status: 'error', errors: 'The last member of the "scoreRange" must be "_".', percent: 0, }; } } if (this.between(score, parseFloat(range[index - 1]), parseFloat(range[index]))) { stat = this.scoreRange[range[index]]; break; } } } var percent = (score * 100) / parseFloat(range[range.length - 2]); var data = { score: score, status: stat, percent: percent >= 100 ? 100 : percent, }; if (skipReq) { data = Object.assign(data, { errors: req }); } return data; } return { score: 0, status: 'Empty', percent: 0, }; }; return PasswordMeter; }()); exports.PasswordMeter = PasswordMeter; //# sourceMappingURL=index.cjs.map