You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1222 lines
33 KiB

3 years ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
  1. /*!
  2. * jQuery Password Strength plugin for Twitter Bootstrap
  3. * Version: 3.1.1
  4. *
  5. * Copyright (c) 2008-2013 Tane Piper
  6. * Copyright (c) 2013 Alejandro Blanco
  7. * Dual licensed under the MIT and GPL licenses.
  8. */
  9. (function (jQuery) {
  10. // Source: src/i18n.js
  11. // eslint-disable-next-line no-implicit-globals
  12. var i18n = {};
  13. (function(i18next) {
  14. 'use strict';
  15. i18n.fallback = {
  16. wordMinLength: 'Your password is too short',
  17. wordMaxLength: 'Your password is too long',
  18. wordInvalidChar: 'Your password contains an invalid character',
  19. wordNotEmail: 'Do not use your email as your password',
  20. wordSimilarToUsername: 'Your password cannot contain your username',
  21. wordTwoCharacterClasses: 'Use different character classes',
  22. wordRepetitions: 'Too many repetitions',
  23. wordSequences: 'Your password contains sequences',
  24. errorList: 'Errors:',
  25. veryWeak: 'Very Weak',
  26. weak: 'Weak',
  27. normal: 'Normal',
  28. medium: 'Medium',
  29. strong: 'Strong',
  30. veryStrong: 'Very Strong'
  31. };
  32. i18n.t = function(key) {
  33. var result = '';
  34. // Try to use i18next.com
  35. if (i18next) {
  36. result = i18next.t(key);
  37. } else {
  38. // Fallback to english
  39. result = i18n.fallback[key];
  40. }
  41. return result === key ? '' : result;
  42. };
  43. })(window.i18next);
  44. // Source: src/rules.js
  45. // eslint-disable-next-line no-implicit-globals
  46. var rulesEngine = {};
  47. try {
  48. if (!jQuery && module && module.exports) {
  49. var jQuery = require('jquery'),
  50. jsdom = require('jsdom').jsdom;
  51. jQuery = jQuery(jsdom().defaultView);
  52. }
  53. } catch (ignore) {
  54. // Nothing to do
  55. }
  56. (function($) {
  57. 'use strict';
  58. var validation = {};
  59. rulesEngine.forbiddenSequences = [
  60. '0123456789',
  61. 'abcdefghijklmnopqrstuvwxyz',
  62. 'qwertyuiop',
  63. 'asdfghjkl',
  64. 'zxcvbnm',
  65. '!@#$%^&*()_+'
  66. ];
  67. validation.wordNotEmail = function(options, word, score) {
  68. if (
  69. word.match(
  70. /^([\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
  71. )
  72. ) {
  73. return score;
  74. }
  75. return 0;
  76. };
  77. validation.wordMinLength = function(options, word, score) {
  78. var wordlen = word.length,
  79. lenScore = Math.pow(wordlen, options.rules.raisePower);
  80. if (wordlen < options.common.minChar) {
  81. lenScore = lenScore + score;
  82. }
  83. return lenScore;
  84. };
  85. validation.wordMaxLength = function(options, word, score) {
  86. var wordlen = word.length,
  87. lenScore = Math.pow(wordlen, options.rules.raisePower);
  88. if (wordlen > options.common.maxChar) {
  89. return score;
  90. }
  91. return lenScore;
  92. };
  93. validation.wordInvalidChar = function(options, word, score) {
  94. if (options.common.invalidCharsRegExp.test(word)) {
  95. return score;
  96. }
  97. return 0;
  98. };
  99. validation.wordMinLengthStaticScore = function(options, word, score) {
  100. return word.length < options.common.minChar ? 0 : score;
  101. };
  102. validation.wordMaxLengthStaticScore = function(options, word, score) {
  103. return word.length > options.common.maxChar ? 0 : score;
  104. };
  105. validation.wordSimilarToUsername = function(options, word, score) {
  106. var username = $(options.common.usernameField).val();
  107. if (
  108. username &&
  109. word
  110. .toLowerCase()
  111. .match(
  112. username
  113. .replace(/[-[\]/{}()*+=?:.\\^$|!,]/g, '\\$&')
  114. .toLowerCase()
  115. )
  116. ) {
  117. return score;
  118. }
  119. return 0;
  120. };
  121. validation.wordTwoCharacterClasses = function(options, word, score) {
  122. var specialCharRE = new RegExp(
  123. '(.' + options.rules.specialCharClass + ')'
  124. );
  125. if (
  126. word.match(/([a-z].*[A-Z])|([A-Z].*[a-z])/) ||
  127. (word.match(/([a-zA-Z])/) && word.match(/([0-9])/)) ||
  128. (word.match(specialCharRE) && word.match(/[a-zA-Z0-9_]/))
  129. ) {
  130. return score;
  131. }
  132. return;
  133. };
  134. validation.wordRepetitions = function(options, word, score) {
  135. if (word.match(/(.)\1\1/)) {
  136. return score;
  137. }
  138. return 0;
  139. };
  140. validation.wordSequences = function(options, word, score) {
  141. var found = false,
  142. j;
  143. if (word.length > 2) {
  144. $.each(rulesEngine.forbiddenSequences, function(idx, seq) {
  145. var sequences;
  146. if (found) {
  147. return;
  148. }
  149. sequences = [
  150. seq,
  151. seq
  152. .split('')
  153. .reverse()
  154. .join('')
  155. ];
  156. $.each(sequences, function(ignore, sequence) {
  157. for (j = 0; j < word.length - 2; j += 1) {
  158. // iterate the word trough a sliding window of size 3:
  159. if (
  160. sequence.indexOf(
  161. word.toLowerCase().substring(j, j + 3)
  162. ) > -1
  163. ) {
  164. found = true;
  165. }
  166. }
  167. });
  168. });
  169. if (found) {
  170. return score;
  171. }
  172. }
  173. return 0;
  174. };
  175. validation.wordLowercase = function(options, word, score) {
  176. return word.match(/[a-z]/) && score;
  177. };
  178. validation.wordUppercase = function(options, word, score) {
  179. return word.match(/[A-Z]/) && score;
  180. };
  181. validation.wordOneNumber = function(options, word, score) {
  182. return word.match(/\d+/) && score;
  183. };
  184. validation.wordThreeNumbers = function(options, word, score) {
  185. return word.match(/(.*[0-9].*[0-9].*[0-9])/) && score;
  186. };
  187. validation.wordOneSpecialChar = function(options, word, score) {
  188. var specialCharRE = new RegExp(options.rules.specialCharClass);
  189. return word.match(specialCharRE) && score;
  190. };
  191. validation.wordTwoSpecialChar = function(options, word, score) {
  192. var twoSpecialCharRE = new RegExp(
  193. '(.*' +
  194. options.rules.specialCharClass +
  195. '.*' +
  196. options.rules.specialCharClass +
  197. ')'
  198. );
  199. return word.match(twoSpecialCharRE) && score;
  200. };
  201. validation.wordUpperLowerCombo = function(options, word, score) {
  202. return word.match(/([a-z].*[A-Z])|([A-Z].*[a-z])/) && score;
  203. };
  204. validation.wordLetterNumberCombo = function(options, word, score) {
  205. return word.match(/([a-zA-Z])/) && word.match(/([0-9])/) && score;
  206. };
  207. validation.wordLetterNumberCharCombo = function(options, word, score) {
  208. var letterNumberCharComboRE = new RegExp(
  209. '([a-zA-Z0-9].*' +
  210. options.rules.specialCharClass +
  211. ')|(' +
  212. options.rules.specialCharClass +
  213. '.*[a-zA-Z0-9])'
  214. );
  215. return word.match(letterNumberCharComboRE) && score;
  216. };
  217. validation.wordIsACommonPassword = function(options, word, score) {
  218. if ($.inArray(word, options.rules.commonPasswords) >= 0) {
  219. return score;
  220. }
  221. return 0;
  222. };
  223. rulesEngine.validation = validation;
  224. rulesEngine.executeRules = function(options, word) {
  225. var totalScore = 0;
  226. $.each(options.rules.activated, function(rule, active) {
  227. var score, funct, result, errorMessage;
  228. if (active) {
  229. score = options.rules.scores[rule];
  230. funct = rulesEngine.validation[rule];
  231. if (typeof funct !== 'function') {
  232. funct = options.rules.extra[rule];
  233. }
  234. if (typeof funct === 'function') {
  235. result = funct(options, word, score);
  236. if (result) {
  237. totalScore += result;
  238. }
  239. if (result < 0 || (!$.isNumeric(result) && !result)) {
  240. errorMessage = options.ui.spanError(options, rule);
  241. if (errorMessage.length > 0) {
  242. options.instances.errors.push(errorMessage);
  243. }
  244. }
  245. }
  246. }
  247. });
  248. return totalScore;
  249. };
  250. })(jQuery);
  251. try {
  252. if (module && module.exports) {
  253. module.exports = rulesEngine;
  254. }
  255. } catch (ignore) {
  256. // Nothing to do
  257. }
  258. // Source: src/options.js
  259. // eslint-disable-next-line no-implicit-globals
  260. var defaultOptions = {};
  261. defaultOptions.common = {};
  262. defaultOptions.common.minChar = 6;
  263. defaultOptions.common.maxChar = 20;
  264. defaultOptions.common.usernameField = '#username';
  265. defaultOptions.common.invalidCharsRegExp = new RegExp(/[\s,'"]/);
  266. defaultOptions.common.userInputs = [
  267. // Selectors for input fields with user input
  268. ];
  269. defaultOptions.common.onLoad = undefined;
  270. defaultOptions.common.onKeyUp = undefined;
  271. defaultOptions.common.onScore = undefined;
  272. defaultOptions.common.zxcvbn = false;
  273. defaultOptions.common.zxcvbnTerms = [
  274. // List of disrecommended words
  275. ];
  276. defaultOptions.common.events = ['keyup', 'change', 'paste'];
  277. defaultOptions.common.debug = false;
  278. defaultOptions.rules = {};
  279. defaultOptions.rules.extra = {};
  280. defaultOptions.rules.scores = {
  281. wordNotEmail: -100,
  282. wordMinLength: -50,
  283. wordMaxLength: -50,
  284. wordInvalidChar: -100,
  285. wordSimilarToUsername: -100,
  286. wordSequences: -20,
  287. wordTwoCharacterClasses: 2,
  288. wordRepetitions: -25,
  289. wordLowercase: 1,
  290. wordUppercase: 3,
  291. wordOneNumber: 3,
  292. wordThreeNumbers: 5,
  293. wordOneSpecialChar: 3,
  294. wordTwoSpecialChar: 5,
  295. wordUpperLowerCombo: 2,
  296. wordLetterNumberCombo: 2,
  297. wordLetterNumberCharCombo: 2,
  298. wordIsACommonPassword: -100
  299. };
  300. defaultOptions.rules.activated = {
  301. wordNotEmail: true,
  302. wordMinLength: true,
  303. wordMaxLength: false,
  304. wordInvalidChar: false,
  305. wordSimilarToUsername: true,
  306. wordSequences: true,
  307. wordTwoCharacterClasses: true,
  308. wordRepetitions: true,
  309. wordLowercase: true,
  310. wordUppercase: true,
  311. wordOneNumber: true,
  312. wordThreeNumbers: true,
  313. wordOneSpecialChar: true,
  314. wordTwoSpecialChar: true,
  315. wordUpperLowerCombo: true,
  316. wordLetterNumberCombo: true,
  317. wordLetterNumberCharCombo: true,
  318. wordIsACommonPassword: true
  319. };
  320. defaultOptions.rules.raisePower = 1.4;
  321. defaultOptions.rules.specialCharClass = '[!,@,#,$,%,^,&,*,?,_,~]';
  322. // List taken from https://github.com/danielmiessler/SecLists (MIT License)
  323. defaultOptions.rules.commonPasswords = [
  324. '123456',
  325. 'password',
  326. '12345678',
  327. 'qwerty',
  328. '123456789',
  329. '12345',
  330. '1234',
  331. '111111',
  332. '1234567',
  333. 'dragon',
  334. '123123',
  335. 'baseball',
  336. 'abc123',
  337. 'football',
  338. 'monkey',
  339. 'letmein',
  340. '696969',
  341. 'shadow',
  342. 'master',
  343. '666666',
  344. 'qwertyuiop',
  345. '123321',
  346. 'mustang',
  347. '1234567890',
  348. 'michael',
  349. '654321',
  350. 'pussy',
  351. 'superman',
  352. '1qaz2wsx',
  353. '7777777',
  354. 'fuckyou',
  355. '121212',
  356. '000000',
  357. 'qazwsx',
  358. '123qwe',
  359. 'killer',
  360. 'trustno1',
  361. 'jordan',
  362. 'jennifer',
  363. 'zxcvbnm',
  364. 'asdfgh',
  365. 'hunter',
  366. 'buster',
  367. 'soccer',
  368. 'harley',
  369. 'batman',
  370. 'andrew',
  371. 'tigger',
  372. 'sunshine',
  373. 'iloveyou',
  374. 'fuckme',
  375. '2000',
  376. 'charlie',
  377. 'robert',
  378. 'thomas',
  379. 'hockey',
  380. 'ranger',
  381. 'daniel',
  382. 'starwars',
  383. 'klaster',
  384. '112233',
  385. 'george',
  386. 'asshole',
  387. 'computer',
  388. 'michelle',
  389. 'jessica',
  390. 'pepper',
  391. '1111',
  392. 'zxcvbn',
  393. '555555',
  394. '11111111',
  395. '131313',
  396. 'freedom',
  397. '777777',
  398. 'pass',
  399. 'fuck',
  400. 'maggie',
  401. '159753',
  402. 'aaaaaa',
  403. 'ginger',
  404. 'princess',
  405. 'joshua',
  406. 'cheese',
  407. 'amanda',
  408. 'summer',
  409. 'love',
  410. 'ashley',
  411. '6969',
  412. 'nicole',
  413. 'chelsea',
  414. 'biteme',
  415. 'matthew',
  416. 'access',
  417. 'yankees',
  418. '987654321',
  419. 'dallas',
  420. 'austin',
  421. 'thunder',
  422. 'taylor',
  423. 'matrix'
  424. ];
  425. defaultOptions.ui = {};
  426. defaultOptions.ui.bootstrap2 = false;
  427. defaultOptions.ui.bootstrap3 = false;
  428. defaultOptions.ui.colorClasses = [
  429. 'danger',
  430. 'danger',
  431. 'danger',
  432. 'warning',
  433. 'warning',
  434. 'success'
  435. ];
  436. defaultOptions.ui.showProgressBar = true;
  437. defaultOptions.ui.progressBarEmptyPercentage = 1;
  438. defaultOptions.ui.progressBarMinWidth = 1;
  439. defaultOptions.ui.progressBarMinPercentage = 1;
  440. defaultOptions.ui.progressExtraCssClasses = '';
  441. defaultOptions.ui.progressBarExtraCssClasses = '';
  442. defaultOptions.ui.showPopover = false;
  443. defaultOptions.ui.popoverPlacement = 'bottom';
  444. defaultOptions.ui.showStatus = false;
  445. defaultOptions.ui.spanError = function(options, key) {
  446. 'use strict';
  447. var text = options.i18n.t(key);
  448. if (!text) {
  449. return '';
  450. }
  451. return '<span style="color: #d52929">' + text + '</span>';
  452. };
  453. defaultOptions.ui.popoverError = function(options) {
  454. 'use strict';
  455. var errors = options.instances.errors,
  456. errorsTitle = options.i18n.t('errorList'),
  457. message =
  458. '<div>' +
  459. errorsTitle +
  460. '<ul class="error-list" style="margin-bottom: 0;">';
  461. jQuery.each(errors, function(idx, err) {
  462. message += '<li>' + err + '</li>';
  463. });
  464. message += '</ul></div>';
  465. return message;
  466. };
  467. defaultOptions.ui.showVerdicts = true;
  468. defaultOptions.ui.showVerdictsInsideProgressBar = false;
  469. defaultOptions.ui.useVerdictCssClass = false;
  470. defaultOptions.ui.showErrors = false;
  471. defaultOptions.ui.showScore = false;
  472. defaultOptions.ui.container = undefined;
  473. defaultOptions.ui.viewports = {
  474. progress: undefined,
  475. verdict: undefined,
  476. errors: undefined,
  477. score: undefined
  478. };
  479. defaultOptions.ui.scores = [0, 14, 26, 38, 50];
  480. defaultOptions.i18n = {};
  481. defaultOptions.i18n.t = i18n.t;
  482. // Source: src/ui.js
  483. // eslint-disable-next-line no-implicit-globals
  484. var ui = {};
  485. (function($) {
  486. 'use strict';
  487. var statusClasses = ['error', 'warning', 'success'],
  488. verdictKeys = [
  489. 'veryWeak',
  490. 'weak',
  491. 'normal',
  492. 'medium',
  493. 'strong',
  494. 'veryStrong'
  495. ];
  496. ui.getContainer = function(options, $el) {
  497. var $container;
  498. $container = $(options.ui.container);
  499. if (!($container && $container.length === 1)) {
  500. $container = $el.parent();
  501. }
  502. return $container;
  503. };
  504. ui.findElement = function($container, viewport, cssSelector) {
  505. if (viewport) {
  506. return $container.find(viewport).find(cssSelector);
  507. }
  508. return $container.find(cssSelector);
  509. };
  510. ui.getUIElements = function(options, $el) {
  511. var $container, result;
  512. if (options.instances.viewports) {
  513. return options.instances.viewports;
  514. }
  515. $container = ui.getContainer(options, $el);
  516. result = {};
  517. result.$progressbar = ui.findElement(
  518. $container,
  519. options.ui.viewports.progress,
  520. 'div.progress'
  521. );
  522. if (options.ui.showVerdictsInsideProgressBar) {
  523. result.$verdict = result.$progressbar.find('span.password-verdict');
  524. }
  525. if (!options.ui.showPopover) {
  526. if (!options.ui.showVerdictsInsideProgressBar) {
  527. result.$verdict = ui.findElement(
  528. $container,
  529. options.ui.viewports.verdict,
  530. 'span.password-verdict'
  531. );
  532. }
  533. result.$errors = ui.findElement(
  534. $container,
  535. options.ui.viewports.errors,
  536. 'ul.error-list'
  537. );
  538. }
  539. result.$score = ui.findElement(
  540. $container,
  541. options.ui.viewports.score,
  542. 'span.password-score'
  543. );
  544. options.instances.viewports = result;
  545. return result;
  546. };
  547. ui.initHelper = function(options, $el, html, viewport) {
  548. var $container = ui.getContainer(options, $el);
  549. if (viewport) {
  550. $container.find(viewport).append(html);
  551. } else {
  552. $(html).insertAfter($el);
  553. }
  554. };
  555. ui.initVerdict = function(options, $el) {
  556. ui.initHelper(
  557. options,
  558. $el,
  559. '<span class="password-verdict"></span>',
  560. options.ui.viewports.verdict
  561. );
  562. };
  563. ui.initErrorList = function(options, $el) {
  564. ui.initHelper(
  565. options,
  566. $el,
  567. '<ul class="error-list"></ul>',
  568. options.ui.viewports.errors
  569. );
  570. };
  571. ui.initScore = function(options, $el) {
  572. ui.initHelper(
  573. options,
  574. $el,
  575. '<span class="password-score"></span>',
  576. options.ui.viewports.score
  577. );
  578. };
  579. ui.initUI = function(options, $el) {
  580. if (options.ui.showPopover) {
  581. ui.initPopover(options, $el);
  582. } else {
  583. if (options.ui.showErrors) {
  584. ui.initErrorList(options, $el);
  585. }
  586. if (
  587. options.ui.showVerdicts &&
  588. !options.ui.showVerdictsInsideProgressBar
  589. ) {
  590. ui.initVerdict(options, $el);
  591. }
  592. }
  593. if (options.ui.showProgressBar) {
  594. ui.initProgressBar(options, $el);
  595. }
  596. if (options.ui.showScore) {
  597. ui.initScore(options, $el);
  598. }
  599. };
  600. ui.updateVerdict = function(options, $el, cssClass, text) {
  601. var $verdict = ui.getUIElements(options, $el).$verdict;
  602. $verdict.removeClass(options.ui.colorClasses.join(' '));
  603. if (cssClass > -1) {
  604. $verdict.addClass(options.ui.colorClasses[cssClass]);
  605. }
  606. if (options.ui.showVerdictsInsideProgressBar) {
  607. $verdict.css('white-space', 'nowrap');
  608. }
  609. $verdict.html(text);
  610. };
  611. ui.updateErrors = function(options, $el, remove) {
  612. var $errors = ui.getUIElements(options, $el).$errors,
  613. html = '';
  614. if (!remove) {
  615. $.each(options.instances.errors, function(idx, err) {
  616. html += '<li>' + err + '</li>';
  617. });
  618. }
  619. $errors.html(html);
  620. };
  621. ui.updateScore = function(options, $el, score, remove) {
  622. var $score = ui.getUIElements(options, $el).$score,
  623. html = '';
  624. if (!remove) {
  625. html = score.toFixed(2);
  626. }
  627. $score.html(html);
  628. };
  629. ui.updateFieldStatus = function(options, $el, cssClass, remove) {
  630. var $target = $el;
  631. if (options.ui.bootstrap2) {
  632. $target = $el.parents('.control-group').first();
  633. } else if (options.ui.bootstrap3) {
  634. $target = $el.parents('.form-group').first();
  635. }
  636. $.each(statusClasses, function(idx, css) {
  637. css = ui.cssClassesForBS(options, css);
  638. $target.removeClass(css);
  639. });
  640. if (remove) {
  641. return;
  642. }
  643. cssClass = statusClasses[Math.floor(cssClass / 2)];
  644. cssClass = ui.cssClassesForBS(options, cssClass);
  645. $target.addClass(cssClass);
  646. };
  647. ui.cssClassesForBS = function(options, css) {
  648. if (options.ui.bootstrap3) {
  649. css = 'has-' + css;
  650. } else if (!options.ui.bootstrap2) {
  651. // BS4
  652. if (css === 'error') {
  653. css = 'danger';
  654. }
  655. css = 'border-' + css;
  656. }
  657. return css;
  658. };
  659. ui.getVerdictAndCssClass = function(options, score) {
  660. var level, verdict;
  661. if (score === undefined) {
  662. return ['', 0];
  663. }
  664. if (score <= options.ui.scores[0]) {
  665. level = 0;
  666. } else if (score < options.ui.scores[1]) {
  667. level = 1;
  668. } else if (score < options.ui.scores[2]) {
  669. level = 2;
  670. } else if (score < options.ui.scores[3]) {
  671. level = 3;
  672. } else if (score < options.ui.scores[4]) {
  673. level = 4;
  674. } else {
  675. level = 5;
  676. }
  677. verdict = verdictKeys[level];
  678. return [options.i18n.t(verdict), level];
  679. };
  680. ui.updateUI = function(options, $el, score) {
  681. var cssClass, verdictText, verdictCssClass;
  682. cssClass = ui.getVerdictAndCssClass(options, score);
  683. verdictText = score === 0 ? '' : cssClass[0];
  684. cssClass = cssClass[1];
  685. verdictCssClass = options.ui.useVerdictCssClass ? cssClass : -1;
  686. if (options.ui.showProgressBar) {
  687. ui.showProgressBar(
  688. options,
  689. $el,
  690. score,
  691. cssClass,
  692. verdictCssClass,
  693. verdictText
  694. );
  695. }
  696. if (options.ui.showStatus) {
  697. ui.updateFieldStatus(options, $el, cssClass, score === undefined);
  698. }
  699. if (options.ui.showPopover) {
  700. ui.updatePopover(options, $el, verdictText, score === undefined);
  701. } else {
  702. if (
  703. options.ui.showVerdicts &&
  704. !options.ui.showVerdictsInsideProgressBar
  705. ) {
  706. ui.updateVerdict(options, $el, verdictCssClass, verdictText);
  707. }
  708. if (options.ui.showErrors) {
  709. ui.updateErrors(options, $el, score === undefined);
  710. }
  711. }
  712. if (options.ui.showScore) {
  713. ui.updateScore(options, $el, score, score === undefined);
  714. }
  715. };
  716. })(jQuery);
  717. // Source: src/ui.progressbar.js
  718. (function($) {
  719. 'use strict';
  720. ui.percentage = function(options, score, maximun) {
  721. var result = Math.floor((100 * score) / maximun),
  722. min = options.ui.progressBarMinPercentage;
  723. result = result <= min ? min : result;
  724. result = result > 100 ? 100 : result;
  725. return result;
  726. };
  727. ui.initProgressBar = function(options, $el) {
  728. var $container = ui.getContainer(options, $el),
  729. progressbar = '<div class="progress ';
  730. if (options.ui.bootstrap2) {
  731. // Boostrap 2
  732. progressbar +=
  733. options.ui.progressBarExtraCssClasses + '"><div class="';
  734. } else {
  735. // Bootstrap 3 & 4
  736. progressbar +=
  737. options.ui.progressExtraCssClasses +
  738. '"><div class="' +
  739. options.ui.progressBarExtraCssClasses +
  740. ' progress-';
  741. }
  742. progressbar += 'bar">';
  743. if (options.ui.showVerdictsInsideProgressBar) {
  744. progressbar += '<span class="password-verdict"></span>';
  745. }
  746. progressbar += '</div></div>';
  747. if (options.ui.viewports.progress) {
  748. $container.find(options.ui.viewports.progress).append(progressbar);
  749. } else {
  750. $(progressbar).insertAfter($el);
  751. }
  752. };
  753. ui.showProgressBar = function(
  754. options,
  755. $el,
  756. score,
  757. cssClass,
  758. verdictCssClass,
  759. verdictText
  760. ) {
  761. var barPercentage;
  762. if (score === undefined) {
  763. barPercentage = options.ui.progressBarEmptyPercentage;
  764. } else {
  765. barPercentage = ui.percentage(options, score, options.ui.scores[4]);
  766. }
  767. ui.updateProgressBar(options, $el, cssClass, barPercentage);
  768. if (options.ui.showVerdictsInsideProgressBar) {
  769. ui.updateVerdict(options, $el, verdictCssClass, verdictText);
  770. }
  771. };
  772. ui.updateProgressBar = function(options, $el, cssClass, percentage) {
  773. var $progressbar = ui.getUIElements(options, $el).$progressbar,
  774. $bar = $progressbar.find('.progress-bar'),
  775. cssPrefix = 'progress-';
  776. if (options.ui.bootstrap2) {
  777. $bar = $progressbar.find('.bar');
  778. cssPrefix = '';
  779. }
  780. $.each(options.ui.colorClasses, function(idx, value) {
  781. if (options.ui.bootstrap2 || options.ui.bootstrap3) {
  782. $bar.removeClass(cssPrefix + 'bar-' + value);
  783. } else {
  784. $bar.removeClass('bg-' + value);
  785. }
  786. });
  787. if (options.ui.bootstrap2 || options.ui.bootstrap3) {
  788. $bar.addClass(
  789. cssPrefix + 'bar-' + options.ui.colorClasses[cssClass]
  790. );
  791. } else {
  792. $bar.addClass('bg-' + options.ui.colorClasses[cssClass]);
  793. }
  794. if (percentage > 0) {
  795. $bar.css('min-width', options.ui.progressBarMinWidth + 'px');
  796. } else {
  797. $bar.css('min-width', '');
  798. }
  799. $bar.css('width', percentage + '%');
  800. };
  801. })(jQuery);
  802. // Source: src/ui.popover.js
  803. (function() {
  804. 'use strict';
  805. ui.initPopover = function(options, $el) {
  806. try {
  807. $el.popover('destroy');
  808. } catch (error) {
  809. // Bootstrap 4.2.X onwards
  810. $el.popover('dispose');
  811. }
  812. $el.popover({
  813. html: true,
  814. placement: options.ui.popoverPlacement,
  815. trigger: 'manual',
  816. content: ' '
  817. });
  818. };
  819. ui.updatePopover = function(options, $el, verdictText, remove) {
  820. var popover = $el.data('bs.popover'),
  821. html = '',
  822. hide = true,
  823. bootstrap5 = false,
  824. itsVisible = false;
  825. if (
  826. options.ui.showVerdicts &&
  827. !options.ui.showVerdictsInsideProgressBar &&
  828. verdictText.length > 0
  829. ) {
  830. html =
  831. '<h5><span class="password-verdict">' +
  832. verdictText +
  833. '</span></h5>';
  834. hide = false;
  835. }
  836. if (options.ui.showErrors) {
  837. if (options.instances.errors.length > 0) {
  838. hide = false;
  839. }
  840. html += options.ui.popoverError(options);
  841. }
  842. if (hide || remove) {
  843. $el.popover('hide');
  844. return;
  845. }
  846. if (options.ui.bootstrap2) {
  847. popover = $el.data('popover');
  848. } else if (!popover) {
  849. // Bootstrap 5
  850. popover = bootstrap.Popover.getInstance($el[0]);
  851. bootstrap5 = true;
  852. }
  853. if (bootstrap5) {
  854. itsVisible = $(popover.tip).is(':visible');
  855. } else {
  856. itsVisible = popover.$arrow && popover.$arrow.parents('body').length > 0;
  857. }
  858. if (itsVisible) {
  859. if (bootstrap5) {
  860. $(popover.tip).find('.popover-body').html(html);
  861. } else {
  862. $el.find('+ .popover .popover-content').html(html);
  863. }
  864. } else {
  865. // It's hidden
  866. if (options.ui.bootstrap2 || options.ui.bootstrap3) {
  867. popover.options.content = html;
  868. } else if (bootstrap5) {
  869. popover._config.content = html;
  870. } else {
  871. popover.config.content = html;
  872. }
  873. $el.popover('show');
  874. }
  875. };
  876. })();
  877. // Source: src/methods.js
  878. // eslint-disable-next-line no-implicit-globals
  879. var methods = {};
  880. (function($) {
  881. 'use strict';
  882. var onKeyUp, onPaste, applyToAll;
  883. onKeyUp = function(event) {
  884. var $el = $(event.target),
  885. options = $el.data('pwstrength-bootstrap'),
  886. word = $el.val(),
  887. userInputs,
  888. verdictText,
  889. verdictLevel,
  890. score;
  891. if (options === undefined) {
  892. return;
  893. }
  894. options.instances.errors = [];
  895. if (word.length === 0) {
  896. score = undefined;
  897. } else {
  898. if (options.common.zxcvbn) {
  899. userInputs = [];
  900. $.each(
  901. options.common.userInputs.concat([
  902. options.common.usernameField
  903. ]),
  904. function(idx, selector) {
  905. var value = $(selector).val();
  906. if (value) {
  907. userInputs.push(value);
  908. }
  909. }
  910. );
  911. userInputs = userInputs.concat(options.common.zxcvbnTerms);
  912. score = zxcvbn(word, userInputs).guesses;
  913. score = Math.log(score) * Math.LOG2E;
  914. } else {
  915. score = rulesEngine.executeRules(options, word);
  916. }
  917. if (typeof options.common.onScore === 'function') {
  918. score = options.common.onScore(options, word, score);
  919. }
  920. }
  921. ui.updateUI(options, $el, score);
  922. verdictText = ui.getVerdictAndCssClass(options, score);
  923. verdictLevel = verdictText[1];
  924. verdictText = verdictText[0];
  925. if (options.common.debug) {
  926. console.log(score + ' - ' + verdictText);
  927. }
  928. if (typeof options.common.onKeyUp === 'function') {
  929. options.common.onKeyUp(event, {
  930. score: score,
  931. verdictText: verdictText,
  932. verdictLevel: verdictLevel
  933. });
  934. }
  935. };
  936. onPaste = function(event) {
  937. // This handler is necessary because the paste event fires before the
  938. // content is actually in the input, so we cannot read its value right
  939. // away. Therefore, the timeouts.
  940. var $el = $(event.target),
  941. word = $el.val(),
  942. tries = 0,
  943. callback;
  944. callback = function() {
  945. var newWord = $el.val();
  946. if (newWord !== word) {
  947. onKeyUp(event);
  948. } else if (tries < 3) {
  949. tries += 1;
  950. setTimeout(callback, 100);
  951. }
  952. };
  953. setTimeout(callback, 100);
  954. };
  955. methods.init = function(settings) {
  956. this.each(function(idx, el) {
  957. // Make it deep extend (first param) so it extends also the
  958. // rules and other inside objects
  959. var clonedDefaults = $.extend(true, {}, defaultOptions),
  960. localOptions = $.extend(true, clonedDefaults, settings),
  961. $el = $(el);
  962. localOptions.instances = {};
  963. $el.data('pwstrength-bootstrap', localOptions);
  964. $.each(localOptions.common.events, function(ignore, eventName) {
  965. var handler = eventName === 'paste' ? onPaste : onKeyUp;
  966. $el.on(eventName, handler);
  967. });
  968. ui.initUI(localOptions, $el);
  969. $el.trigger('keyup');
  970. if (typeof localOptions.common.onLoad === 'function') {
  971. localOptions.common.onLoad();
  972. }
  973. });
  974. return this;
  975. };
  976. methods.destroy = function() {
  977. this.each(function(idx, el) {
  978. var $el = $(el),
  979. options = $el.data('pwstrength-bootstrap'),
  980. elements = ui.getUIElements(options, $el);
  981. elements.$progressbar.remove();
  982. elements.$verdict.remove();
  983. elements.$errors.remove();
  984. $el.removeData('pwstrength-bootstrap');
  985. });
  986. return this;
  987. };
  988. methods.forceUpdate = function() {
  989. this.each(function(idx, el) {
  990. var event = { target: el };
  991. onKeyUp(event);
  992. });
  993. return this;
  994. };
  995. methods.addRule = function(name, method, score, active) {
  996. this.each(function(idx, el) {
  997. var options = $(el).data('pwstrength-bootstrap');
  998. options.rules.activated[name] = active;
  999. options.rules.scores[name] = score;
  1000. options.rules.extra[name] = method;
  1001. });
  1002. return this;
  1003. };
  1004. applyToAll = function(rule, prop, value) {
  1005. this.each(function(idx, el) {
  1006. $(el).data('pwstrength-bootstrap').rules[prop][rule] = value;
  1007. });
  1008. };
  1009. methods.changeScore = function(rule, score) {
  1010. applyToAll.call(this, rule, 'scores', score);
  1011. return this;
  1012. };
  1013. methods.ruleActive = function(rule, active) {
  1014. applyToAll.call(this, rule, 'activated', active);
  1015. return this;
  1016. };
  1017. methods.ruleIsMet = function(rule) {
  1018. var rulesMetCnt = 0;
  1019. if (rule === 'wordMinLength') {
  1020. rule = 'wordMinLengthStaticScore';
  1021. } else if (rule === 'wordMaxLength') {
  1022. rule = 'wordMaxLengthStaticScore';
  1023. }
  1024. this.each(function(idx, el) {
  1025. var options = $(el).data('pwstrength-bootstrap'),
  1026. ruleFunction = rulesEngine.validation[rule],
  1027. result;
  1028. if (typeof ruleFunction !== 'function') {
  1029. ruleFunction = options.rules.extra[rule];
  1030. }
  1031. if (typeof ruleFunction === 'function') {
  1032. result = ruleFunction(options, $(el).val(), 1);
  1033. if ($.isNumeric(result)) {
  1034. rulesMetCnt += result;
  1035. }
  1036. }
  1037. });
  1038. return rulesMetCnt === this.length;
  1039. };
  1040. $.fn.pwstrength = function(method) {
  1041. var result;
  1042. if (methods[method]) {
  1043. result = methods[method].apply(
  1044. this,
  1045. Array.prototype.slice.call(arguments, 1)
  1046. );
  1047. } else if (typeof method === 'object' || !method) {
  1048. result = methods.init.apply(this, arguments);
  1049. } else {
  1050. $.error(
  1051. 'Method ' +
  1052. method +
  1053. ' does not exist on jQuery.pwstrength-bootstrap'
  1054. );
  1055. }
  1056. return result;
  1057. };
  1058. })(jQuery);
  1059. }(jQuery));