pwstrength-bootstrap.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804
  1. /*!
  2. * jQuery Password Strength plugin for Twitter Bootstrap
  3. * Version: 2.0.6
  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. var i18n = {};
  12. (function (i18n, i18next) {
  13. 'use strict';
  14. i18n.fallback = {
  15. "wordLength": "Your password is too short",
  16. "wordNotEmail": "Do not use your email as your password",
  17. "wordSimilarToUsername": "Your password cannot contain your username",
  18. "wordTwoCharacterClasses": "Use different character classes",
  19. "wordRepetitions": "Too many repetitions",
  20. "wordSequences": "Your password contains sequences",
  21. "errorList": "Errors:",
  22. "veryWeak": "Very Weak",
  23. "weak": "Weak",
  24. "normal": "Normal",
  25. "medium": "Medium",
  26. "strong": "Strong",
  27. "veryStrong": "Very Strong"
  28. };
  29. i18n.t = function (key) {
  30. var result = '';
  31. // Try to use i18next.com
  32. if (i18next) {
  33. result = i18next.t(key);
  34. } else {
  35. // Fallback to english
  36. result = i18n.fallback[key];
  37. }
  38. return result === key ? '' : result;
  39. };
  40. }(i18n, window.i18next));
  41. // Source: src/rules.js
  42. var rulesEngine = {};
  43. try {
  44. if (!jQuery && module && module.exports) {
  45. var jQuery = require("jquery"),
  46. jsdom = require("jsdom").jsdom;
  47. jQuery = jQuery(jsdom().defaultView);
  48. }
  49. } catch (ignore) {}
  50. (function ($, rulesEngine) {
  51. "use strict";
  52. var validation = {};
  53. rulesEngine.forbiddenSequences = [
  54. "0123456789", "abcdefghijklmnopqrstuvwxyz", "qwertyuiop", "asdfghjkl",
  55. "zxcvbnm", "!@#$%^&*()_+"
  56. ];
  57. validation.wordNotEmail = function (options, word, score) {
  58. 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)) {
  59. return score;
  60. }
  61. return 0;
  62. };
  63. validation.wordLength = function (options, word, score) {
  64. var wordlen = word.length,
  65. lenScore = Math.pow(wordlen, options.rules.raisePower);
  66. if (wordlen < options.common.minChar) {
  67. lenScore = (lenScore + score);
  68. }
  69. return lenScore;
  70. };
  71. validation.wordSimilarToUsername = function (options, word, score) {
  72. var username = $(options.common.usernameField).val();
  73. if (username && word.toLowerCase().match(username.replace(/[\-\[\]\/\{\}\(\)\*\+\=\?\:\.\\\^\$\|\!\,]/g, "\\$&").toLowerCase())) {
  74. return score;
  75. }
  76. return 0;
  77. };
  78. validation.wordTwoCharacterClasses = function (options, word, score) {
  79. if (word.match(/([a-z].*[A-Z])|([A-Z].*[a-z])/) ||
  80. (word.match(/([a-zA-Z])/) && word.match(/([0-9])/)) ||
  81. (word.match(/(.[!,@,#,$,%,\^,&,*,?,_,~])/) && word.match(/[a-zA-Z0-9_]/))) {
  82. return score;
  83. }
  84. return 0;
  85. };
  86. validation.wordRepetitions = function (options, word, score) {
  87. if (word.match(/(.)\1\1/)) { return score; }
  88. return 0;
  89. };
  90. validation.wordSequences = function (options, word, score) {
  91. var found = false,
  92. j;
  93. if (word.length > 2) {
  94. $.each(rulesEngine.forbiddenSequences, function (idx, seq) {
  95. if (found) { return; }
  96. var sequences = [seq, seq.split('').reverse().join('')];
  97. $.each(sequences, function (idx, sequence) {
  98. for (j = 0; j < (word.length - 2); j += 1) { // iterate the word trough a sliding window of size 3:
  99. if (sequence.indexOf(word.toLowerCase().substring(j, j + 3)) > -1) {
  100. found = true;
  101. }
  102. }
  103. });
  104. });
  105. if (found) { return score; }
  106. }
  107. return 0;
  108. };
  109. validation.wordLowercase = function (options, word, score) {
  110. return word.match(/[a-z]/) && score;
  111. };
  112. validation.wordUppercase = function (options, word, score) {
  113. return word.match(/[A-Z]/) && score;
  114. };
  115. validation.wordOneNumber = function (options, word, score) {
  116. return word.match(/\d+/) && score;
  117. };
  118. validation.wordThreeNumbers = function (options, word, score) {
  119. return word.match(/(.*[0-9].*[0-9].*[0-9])/) && score;
  120. };
  121. validation.wordOneSpecialChar = function (options, word, score) {
  122. return word.match(/[!,@,#,$,%,\^,&,*,?,_,~]/) && score;
  123. };
  124. validation.wordTwoSpecialChar = function (options, word, score) {
  125. return word.match(/(.*[!,@,#,$,%,\^,&,*,?,_,~].*[!,@,#,$,%,\^,&,*,?,_,~])/) && score;
  126. };
  127. validation.wordUpperLowerCombo = function (options, word, score) {
  128. return word.match(/([a-z].*[A-Z])|([A-Z].*[a-z])/) && score;
  129. };
  130. validation.wordLetterNumberCombo = function (options, word, score) {
  131. return word.match(/([a-zA-Z])/) && word.match(/([0-9])/) && score;
  132. };
  133. validation.wordLetterNumberCharCombo = function (options, word, score) {
  134. return word.match(/([a-zA-Z0-9].*[!,@,#,$,%,\^,&,*,?,_,~])|([!,@,#,$,%,\^,&,*,?,_,~].*[a-zA-Z0-9])/) && score;
  135. };
  136. rulesEngine.validation = validation;
  137. rulesEngine.executeRules = function (options, word) {
  138. var totalScore = 0;
  139. $.each(options.rules.activated, function (rule, active) {
  140. if (active) {
  141. var score = options.rules.scores[rule],
  142. funct = rulesEngine.validation[rule],
  143. result,
  144. errorMessage;
  145. if (!$.isFunction(funct)) {
  146. funct = options.rules.extra[rule];
  147. }
  148. if ($.isFunction(funct)) {
  149. result = funct(options, word, score);
  150. if (result) {
  151. totalScore += result;
  152. }
  153. if (result < 0 || (!$.isNumeric(result) && !result)) {
  154. errorMessage = options.ui.spanError(options, rule);
  155. if (errorMessage.length > 0) {
  156. options.instances.errors.push(errorMessage);
  157. }
  158. }
  159. }
  160. }
  161. });
  162. if ($.isFunction(options.common.onScore)) {
  163. totalScore = options.common.onScore(options, word, totalScore);
  164. }
  165. return totalScore;
  166. };
  167. }(jQuery, rulesEngine));
  168. try {
  169. if (module && module.exports) {
  170. module.exports = rulesEngine;
  171. }
  172. } catch (ignore) {}
  173. // Source: src/options.js
  174. var defaultOptions = {};
  175. defaultOptions.common = {};
  176. defaultOptions.common.minChar = 6;
  177. defaultOptions.common.usernameField = "#username";
  178. defaultOptions.common.userInputs = [
  179. // Selectors for input fields with user input
  180. ];
  181. defaultOptions.common.onLoad = undefined;
  182. defaultOptions.common.onKeyUp = undefined;
  183. defaultOptions.common.onScore = undefined;
  184. defaultOptions.common.zxcvbn = false;
  185. defaultOptions.common.zxcvbnTerms = [
  186. // List of disrecommended words
  187. ];
  188. defaultOptions.common.events = ["keyup", "change", "paste"];
  189. defaultOptions.common.debug = false;
  190. defaultOptions.rules = {};
  191. defaultOptions.rules.extra = {};
  192. defaultOptions.rules.scores = {
  193. wordNotEmail: -100,
  194. wordLength: -50,
  195. wordSimilarToUsername: -100,
  196. wordSequences: -20,
  197. wordTwoCharacterClasses: 2,
  198. wordRepetitions: -25,
  199. wordLowercase: 1,
  200. wordUppercase: 3,
  201. wordOneNumber: 3,
  202. wordThreeNumbers: 5,
  203. wordOneSpecialChar: 3,
  204. wordTwoSpecialChar: 5,
  205. wordUpperLowerCombo: 2,
  206. wordLetterNumberCombo: 2,
  207. wordLetterNumberCharCombo: 2
  208. };
  209. defaultOptions.rules.activated = {
  210. wordNotEmail: true,
  211. wordLength: true,
  212. wordSimilarToUsername: true,
  213. wordSequences: true,
  214. wordTwoCharacterClasses: false,
  215. wordRepetitions: false,
  216. wordLowercase: true,
  217. wordUppercase: true,
  218. wordOneNumber: true,
  219. wordThreeNumbers: true,
  220. wordOneSpecialChar: true,
  221. wordTwoSpecialChar: true,
  222. wordUpperLowerCombo: true,
  223. wordLetterNumberCombo: true,
  224. wordLetterNumberCharCombo: true
  225. };
  226. defaultOptions.rules.raisePower = 1.4;
  227. defaultOptions.ui = {};
  228. defaultOptions.ui.bootstrap2 = false;
  229. defaultOptions.ui.bootstrap4 = false;
  230. defaultOptions.ui.colorClasses = [
  231. "danger", "danger", "danger", "warning", "warning", "success"
  232. ];
  233. defaultOptions.ui.showProgressBar = true;
  234. defaultOptions.ui.progressBarEmptyPercentage = 1;
  235. defaultOptions.ui.progressBarMinPercentage = 1;
  236. defaultOptions.ui.progressBarExtraCssClasses = '';
  237. defaultOptions.ui.showPopover = false;
  238. defaultOptions.ui.popoverPlacement = "bottom";
  239. defaultOptions.ui.showStatus = false;
  240. defaultOptions.ui.spanError = function (options, key) {
  241. "use strict";
  242. var text = options.i18n.t(key);
  243. if (!text) { return ''; }
  244. return '<span style="color: #d52929">' + text + '</span>';
  245. };
  246. defaultOptions.ui.popoverError = function (options) {
  247. "use strict";
  248. var errors = options.instances.errors,
  249. errorsTitle = options.i18n.t("errorList"),
  250. message = "<div>" + errorsTitle + "<ul class='error-list' style='margin-bottom: 0;'>";
  251. jQuery.each(errors, function (idx, err) {
  252. message += "<li>" + err + "</li>";
  253. });
  254. message += "</ul></div>";
  255. return message;
  256. };
  257. defaultOptions.ui.showVerdicts = true;
  258. defaultOptions.ui.showVerdictsInsideProgressBar = false;
  259. defaultOptions.ui.useVerdictCssClass = false;
  260. defaultOptions.ui.showErrors = false;
  261. defaultOptions.ui.showScore = false;
  262. defaultOptions.ui.container = undefined;
  263. defaultOptions.ui.viewports = {
  264. progress: undefined,
  265. verdict: undefined,
  266. errors: undefined,
  267. score: undefined
  268. };
  269. defaultOptions.ui.scores = [0, 14, 26, 38, 50];
  270. defaultOptions.i18n = {};
  271. defaultOptions.i18n.t = i18n.t;
  272. // Source: src/ui.js
  273. var ui = {};
  274. (function ($, ui) {
  275. "use strict";
  276. var statusClasses = ["error", "warning", "success"],
  277. verdictKeys = [
  278. "veryWeak", "weak", "normal", "medium", "strong", "veryStrong"
  279. ];
  280. ui.getContainer = function (options, $el) {
  281. var $container;
  282. $container = $(options.ui.container);
  283. if (!($container && $container.length === 1)) {
  284. $container = $el.parent();
  285. }
  286. return $container;
  287. };
  288. ui.findElement = function ($container, viewport, cssSelector) {
  289. if (viewport) {
  290. return $container.find(viewport).find(cssSelector);
  291. }
  292. return $container.find(cssSelector);
  293. };
  294. ui.getUIElements = function (options, $el) {
  295. var $container, result;
  296. if (options.instances.viewports) {
  297. return options.instances.viewports;
  298. }
  299. $container = ui.getContainer(options, $el);
  300. result = {};
  301. result.$progressbar = ui.findElement($container, options.ui.viewports.progress, "div.progress");
  302. if (options.ui.showVerdictsInsideProgressBar) {
  303. result.$verdict = result.$progressbar.find("span.password-verdict");
  304. }
  305. if (!options.ui.showPopover) {
  306. if (!options.ui.showVerdictsInsideProgressBar) {
  307. result.$verdict = ui.findElement($container, options.ui.viewports.verdict, "span.password-verdict");
  308. }
  309. result.$errors = ui.findElement($container, options.ui.viewports.errors, "ul.error-list");
  310. }
  311. result.$score = ui.findElement($container, options.ui.viewports.score,
  312. "span.password-score");
  313. options.instances.viewports = result;
  314. return result;
  315. };
  316. ui.initProgressBar = function (options, $el) {
  317. var $container = ui.getContainer(options, $el),
  318. progressbar = "<div class='progress ";
  319. if (options.ui.bootstrap2) {
  320. // Boostrap 2
  321. progressbar += options.ui.progressBarExtraCssClasses +
  322. "'><div class='";
  323. } else {
  324. // Bootstrap 3 & 4
  325. progressbar += "'><div class='" +
  326. options.ui.progressBarExtraCssClasses + " progress-";
  327. }
  328. progressbar += "bar'>";
  329. if (options.ui.showVerdictsInsideProgressBar) {
  330. progressbar += "<span class='password-verdict'></span>";
  331. }
  332. progressbar += "</div></div>";
  333. if (options.ui.viewports.progress) {
  334. $container.find(options.ui.viewports.progress).append(progressbar);
  335. } else {
  336. $(progressbar).insertAfter($el);
  337. }
  338. };
  339. ui.initHelper = function (options, $el, html, viewport) {
  340. var $container = ui.getContainer(options, $el);
  341. if (viewport) {
  342. $container.find(viewport).append(html);
  343. } else {
  344. $(html).insertAfter($el);
  345. }
  346. };
  347. ui.initVerdict = function (options, $el) {
  348. ui.initHelper(options, $el, "<span class='password-verdict'></span>",
  349. options.ui.viewports.verdict);
  350. };
  351. ui.initErrorList = function (options, $el) {
  352. ui.initHelper(options, $el, "<ul class='error-list'></ul>",
  353. options.ui.viewports.errors);
  354. };
  355. ui.initScore = function (options, $el) {
  356. ui.initHelper(options, $el, "<span class='password-score'></span>",
  357. options.ui.viewports.score);
  358. };
  359. ui.initPopover = function (options, $el) {
  360. $el.popover("destroy");
  361. $el.popover({
  362. html: true,
  363. placement: options.ui.popoverPlacement,
  364. trigger: "manual",
  365. content: " "
  366. });
  367. };
  368. ui.initUI = function (options, $el) {
  369. if (options.ui.showPopover) {
  370. ui.initPopover(options, $el);
  371. } else {
  372. if (options.ui.showErrors) { ui.initErrorList(options, $el); }
  373. if (options.ui.showVerdicts && !options.ui.showVerdictsInsideProgressBar) {
  374. ui.initVerdict(options, $el);
  375. }
  376. }
  377. if (options.ui.showProgressBar) {
  378. ui.initProgressBar(options, $el);
  379. }
  380. if (options.ui.showScore) {
  381. ui.initScore(options, $el);
  382. }
  383. };
  384. ui.updateProgressBar = function (options, $el, cssClass, percentage) {
  385. var $progressbar = ui.getUIElements(options, $el).$progressbar,
  386. $bar = $progressbar.find(".progress-bar"),
  387. cssPrefix = "progress-";
  388. if (options.ui.bootstrap2) {
  389. $bar = $progressbar.find(".bar");
  390. cssPrefix = "";
  391. }
  392. $.each(options.ui.colorClasses, function (idx, value) {
  393. if (options.ui.bootstrap4) {
  394. $bar.removeClass("bg-" + value);
  395. } else {
  396. $bar.removeClass(cssPrefix + "bar-" + value);
  397. }
  398. });
  399. if (options.ui.bootstrap4) {
  400. $bar.addClass("bg-" + options.ui.colorClasses[cssClass]);
  401. } else {
  402. $bar.addClass(cssPrefix + "bar-" + options.ui.colorClasses[cssClass]);
  403. }
  404. $bar.css("width", percentage + '%');
  405. };
  406. ui.updateVerdict = function (options, $el, cssClass, text) {
  407. var $verdict = ui.getUIElements(options, $el).$verdict;
  408. $verdict.removeClass(options.ui.colorClasses.join(' '));
  409. if (cssClass > -1) {
  410. $verdict.addClass(options.ui.colorClasses[cssClass]);
  411. }
  412. $verdict.html(text);
  413. };
  414. ui.updateErrors = function (options, $el, remove) {
  415. var $errors = ui.getUIElements(options, $el).$errors,
  416. html = "";
  417. if (!remove) {
  418. $.each(options.instances.errors, function (idx, err) {
  419. html += "<li>" + err + "</li>";
  420. });
  421. }
  422. $errors.html(html);
  423. };
  424. ui.updateScore = function (options, $el, score, remove) {
  425. var $score = ui.getUIElements(options, $el).$score,
  426. html = "";
  427. if (!remove) { html = score.toFixed(2); }
  428. $score.html(html);
  429. };
  430. ui.updatePopover = function (options, $el, verdictText, remove) {
  431. var popover = $el.data("bs.popover"),
  432. html = "",
  433. hide = true;
  434. if (options.ui.showVerdicts &&
  435. !options.ui.showVerdictsInsideProgressBar &&
  436. verdictText.length > 0) {
  437. html = "<h5><span class='password-verdict'>" + verdictText +
  438. "</span></h5>";
  439. hide = false;
  440. }
  441. if (options.ui.showErrors) {
  442. if (options.instances.errors.length > 0) {
  443. hide = false;
  444. }
  445. html += options.ui.popoverError(options);
  446. }
  447. if (hide || remove) {
  448. $el.popover("hide");
  449. return;
  450. }
  451. if (options.ui.bootstrap2) { popover = $el.data("popover"); }
  452. if (popover.$arrow && popover.$arrow.parents("body").length > 0) {
  453. $el.find("+ .popover .popover-content").html(html);
  454. } else {
  455. // It's hidden
  456. popover.options.content = html;
  457. $el.popover("show");
  458. }
  459. };
  460. ui.updateFieldStatus = function (options, $el, cssClass, remove) {
  461. var targetClass = options.ui.bootstrap2 ? ".control-group" : ".form-group",
  462. $container = $el.parents(targetClass).first();
  463. $.each(statusClasses, function (idx, css) {
  464. if (!options.ui.bootstrap2) { css = "has-" + css; }
  465. $container.removeClass(css);
  466. });
  467. if (remove) { return; }
  468. cssClass = statusClasses[cssClass];
  469. if (!options.ui.bootstrap2) { cssClass = "has-" + cssClass; }
  470. $container.addClass(cssClass);
  471. };
  472. ui.percentage = function (options, score, maximun) {
  473. var result = Math.floor(100 * score / maximun),
  474. min = options.ui.progressBarMinPercentage;
  475. result = result <= min ? min : result;
  476. result = result > 100 ? 100 : result;
  477. return result;
  478. };
  479. ui.getVerdictAndCssClass = function (options, score) {
  480. var level, verdict;
  481. if (score === undefined) { return ['', 0]; }
  482. if (score <= options.ui.scores[0]) {
  483. level = 0;
  484. } else if (score < options.ui.scores[1]) {
  485. level = 1;
  486. } else if (score < options.ui.scores[2]) {
  487. level = 2;
  488. } else if (score < options.ui.scores[3]) {
  489. level = 3;
  490. } else if (score < options.ui.scores[4]) {
  491. level = 4;
  492. } else {
  493. level = 5;
  494. }
  495. verdict = verdictKeys[level];
  496. return [options.i18n.t(verdict), level];
  497. };
  498. ui.updateUI = function (options, $el, score) {
  499. var cssClass, barPercentage, verdictText, verdictCssClass;
  500. cssClass = ui.getVerdictAndCssClass(options, score);
  501. verdictText = score === 0 ? '' : cssClass[0];
  502. cssClass = cssClass[1];
  503. verdictCssClass = options.ui.useVerdictCssClass ? cssClass : -1;
  504. if (options.ui.showProgressBar) {
  505. if (score === undefined) {
  506. barPercentage = options.ui.progressBarEmptyPercentage;
  507. } else {
  508. barPercentage = ui.percentage(options, score, options.ui.scores[4]);
  509. }
  510. ui.updateProgressBar(options, $el, cssClass, barPercentage);
  511. if (options.ui.showVerdictsInsideProgressBar) {
  512. ui.updateVerdict(options, $el, verdictCssClass, verdictText);
  513. }
  514. }
  515. if (options.ui.showStatus) {
  516. ui.updateFieldStatus(options, $el, cssClass, score === undefined);
  517. }
  518. if (options.ui.showPopover) {
  519. ui.updatePopover(options, $el, verdictText, score === undefined);
  520. } else {
  521. if (options.ui.showVerdicts && !options.ui.showVerdictsInsideProgressBar) {
  522. ui.updateVerdict(options, $el, verdictCssClass, verdictText);
  523. }
  524. if (options.ui.showErrors) {
  525. ui.updateErrors(options, $el, score === undefined);
  526. }
  527. }
  528. if (options.ui.showScore) {
  529. ui.updateScore(options, $el, score, score === undefined);
  530. }
  531. };
  532. }(jQuery, ui));
  533. // Source: src/methods.js
  534. var methods = {};
  535. (function ($, methods) {
  536. "use strict";
  537. var onKeyUp, onPaste, applyToAll;
  538. onKeyUp = function (event) {
  539. var $el = $(event.target),
  540. options = $el.data("pwstrength-bootstrap"),
  541. word = $el.val(),
  542. userInputs,
  543. verdictText,
  544. verdictLevel,
  545. score;
  546. if (options === undefined) { return; }
  547. options.instances.errors = [];
  548. if (word.length === 0) {
  549. score = undefined;
  550. } else {
  551. if (options.common.zxcvbn) {
  552. userInputs = [];
  553. $.each(options.common.userInputs.concat([options.common.usernameField]), function (idx, selector) {
  554. var value = $(selector).val();
  555. if (value) { userInputs.push(value); }
  556. });
  557. userInputs = userInputs.concat(options.common.zxcvbnTerms);
  558. score = zxcvbn(word, userInputs).guesses;
  559. score = Math.log(score) * Math.LOG2E;
  560. } else {
  561. score = rulesEngine.executeRules(options, word);
  562. }
  563. }
  564. ui.updateUI(options, $el, score);
  565. verdictText = ui.getVerdictAndCssClass(options, score);
  566. verdictLevel = verdictText[1];
  567. verdictText = verdictText[0];
  568. if (options.common.debug) { console.log(score + ' - ' + verdictText); }
  569. if ($.isFunction(options.common.onKeyUp)) {
  570. options.common.onKeyUp(event, {
  571. score: score,
  572. verdictText: verdictText,
  573. verdictLevel: verdictLevel
  574. });
  575. }
  576. };
  577. onPaste = function (event) {
  578. // This handler is necessary because the paste event fires before the
  579. // content is actually in the input, so we cannot read its value right
  580. // away. Therefore, the timeouts.
  581. var $el = $(event.target),
  582. word = $el.val(),
  583. tries = 0,
  584. callback;
  585. callback = function () {
  586. var newWord = $el.val();
  587. if (newWord !== word) {
  588. onKeyUp(event);
  589. } else if (tries < 3) {
  590. tries += 1;
  591. setTimeout(callback, 100);
  592. }
  593. };
  594. setTimeout(callback, 100);
  595. };
  596. methods.init = function (settings) {
  597. this.each(function (idx, el) {
  598. // Make it deep extend (first param) so it extends also the
  599. // rules and other inside objects
  600. var clonedDefaults = $.extend(true, {}, defaultOptions),
  601. localOptions = $.extend(true, clonedDefaults, settings),
  602. $el = $(el);
  603. localOptions.instances = {};
  604. $el.data("pwstrength-bootstrap", localOptions);
  605. $.each(localOptions.common.events, function (idx, eventName) {
  606. var handler = eventName === "paste" ? onPaste : onKeyUp;
  607. $el.on(eventName, handler);
  608. });
  609. ui.initUI(localOptions, $el);
  610. $el.trigger("keyup");
  611. if ($.isFunction(localOptions.common.onLoad)) {
  612. localOptions.common.onLoad();
  613. }
  614. });
  615. return this;
  616. };
  617. methods.destroy = function () {
  618. this.each(function (idx, el) {
  619. var $el = $(el),
  620. options = $el.data("pwstrength-bootstrap"),
  621. elements = ui.getUIElements(options, $el);
  622. elements.$progressbar.remove();
  623. elements.$verdict.remove();
  624. elements.$errors.remove();
  625. $el.removeData("pwstrength-bootstrap");
  626. });
  627. };
  628. methods.forceUpdate = function () {
  629. this.each(function (idx, el) {
  630. var event = { target: el };
  631. onKeyUp(event);
  632. });
  633. };
  634. methods.addRule = function (name, method, score, active) {
  635. this.each(function (idx, el) {
  636. var options = $(el).data("pwstrength-bootstrap");
  637. options.rules.activated[name] = active;
  638. options.rules.scores[name] = score;
  639. options.rules.extra[name] = method;
  640. });
  641. };
  642. applyToAll = function (rule, prop, value) {
  643. this.each(function (idx, el) {
  644. $(el).data("pwstrength-bootstrap").rules[prop][rule] = value;
  645. });
  646. };
  647. methods.changeScore = function (rule, score) {
  648. applyToAll.call(this, rule, "scores", score);
  649. };
  650. methods.ruleActive = function (rule, active) {
  651. applyToAll.call(this, rule, "activated", active);
  652. };
  653. $.fn.pwstrength = function (method) {
  654. var result;
  655. if (methods[method]) {
  656. result = methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
  657. } else if (typeof method === "object" || !method) {
  658. result = methods.init.apply(this, arguments);
  659. } else {
  660. $.error("Method " + method + " does not exist on jQuery.pwstrength-bootstrap");
  661. }
  662. return result;
  663. };
  664. }(jQuery, methods));
  665. }(jQuery));