isStrongPassword.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. import merge from './util/merge';
  2. import assertString from './util/assertString';
  3. var upperCaseRegex = /^[A-Z]$/;
  4. var lowerCaseRegex = /^[a-z]$/;
  5. var numberRegex = /^[0-9]$/;
  6. var symbolRegex = /^[-#!$@%^&*()_+|~=`{}\[\]:";'<>?,.\/ ]$/;
  7. var defaultOptions = {
  8. minLength: 8,
  9. minLowercase: 1,
  10. minUppercase: 1,
  11. minNumbers: 1,
  12. minSymbols: 1,
  13. returnScore: false,
  14. pointsPerUnique: 1,
  15. pointsPerRepeat: 0.5,
  16. pointsForContainingLower: 10,
  17. pointsForContainingUpper: 10,
  18. pointsForContainingNumber: 10,
  19. pointsForContainingSymbol: 10
  20. };
  21. /* Counts number of occurrences of each char in a string
  22. * could be moved to util/ ?
  23. */
  24. function countChars(str) {
  25. var result = {};
  26. Array.from(str).forEach(function (_char) {
  27. var curVal = result[_char];
  28. if (curVal) {
  29. result[_char] += 1;
  30. } else {
  31. result[_char] = 1;
  32. }
  33. });
  34. return result;
  35. }
  36. /* Return information about a password */
  37. function analyzePassword(password) {
  38. var charMap = countChars(password);
  39. var analysis = {
  40. length: password.length,
  41. uniqueChars: Object.keys(charMap).length,
  42. uppercaseCount: 0,
  43. lowercaseCount: 0,
  44. numberCount: 0,
  45. symbolCount: 0
  46. };
  47. Object.keys(charMap).forEach(function (_char2) {
  48. /* istanbul ignore else */
  49. if (upperCaseRegex.test(_char2)) {
  50. analysis.uppercaseCount += charMap[_char2];
  51. } else if (lowerCaseRegex.test(_char2)) {
  52. analysis.lowercaseCount += charMap[_char2];
  53. } else if (numberRegex.test(_char2)) {
  54. analysis.numberCount += charMap[_char2];
  55. } else if (symbolRegex.test(_char2)) {
  56. analysis.symbolCount += charMap[_char2];
  57. }
  58. });
  59. return analysis;
  60. }
  61. function scorePassword(analysis, scoringOptions) {
  62. var points = 0;
  63. points += analysis.uniqueChars * scoringOptions.pointsPerUnique;
  64. points += (analysis.length - analysis.uniqueChars) * scoringOptions.pointsPerRepeat;
  65. if (analysis.lowercaseCount > 0) {
  66. points += scoringOptions.pointsForContainingLower;
  67. }
  68. if (analysis.uppercaseCount > 0) {
  69. points += scoringOptions.pointsForContainingUpper;
  70. }
  71. if (analysis.numberCount > 0) {
  72. points += scoringOptions.pointsForContainingNumber;
  73. }
  74. if (analysis.symbolCount > 0) {
  75. points += scoringOptions.pointsForContainingSymbol;
  76. }
  77. return points;
  78. }
  79. export default function isStrongPassword(str) {
  80. var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
  81. assertString(str);
  82. var analysis = analyzePassword(str);
  83. options = merge(options || {}, defaultOptions);
  84. if (options.returnScore) {
  85. return scorePassword(analysis, options);
  86. }
  87. return analysis.length >= options.minLength && analysis.lowercaseCount >= options.minLowercase && analysis.uppercaseCount >= options.minUppercase && analysis.numberCount >= options.minNumbers && analysis.symbolCount >= options.minSymbols;
  88. }