web/public/yt/password_strength_lightweight.js   F
last analyzed

Complexity

Total Complexity 184
Complexity/F 2.33

Size

Lines of Code 1214
Function Count 79

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 184
eloc 829
mnd 105
bc 105
fnc 79
dl 0
loc 1214
rs 1.771
bpm 1.3291
cpm 2.3291
noi 7
c 0
b 0
f 0

How to fix   Complexity   

Complexity

Complex classes like web/public/yt/password_strength_lightweight.js often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

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

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
973
                bootstrap5 = true;
974
            }
975
    
976
            if (bootstrap5) {
977
                itsVisible = $(popover.tip).is(':visible');
978
            } else {
979
                itsVisible = popover.$arrow && popover.$arrow.parents('body').length > 0;
980
            }
981
    
982
            if (itsVisible) {
983
                if (bootstrap5) {
984
                    $(popover.tip).find('.popover-body').html(html);
985
                } else {
986
                    $el.find('+ .popover .popover-content').html(html);
987
                }
988
            } else {
989
                // It's hidden
990
                if (options.ui.bootstrap2 || options.ui.bootstrap3) {
991
                    popover.options.content = html;
992
                } else if (bootstrap5) {
993
                    popover._config.content = html;
994
                } else {
995
                    popover.config.content = html;
996
                }
997
                $el.popover('show');
998
            }
999
        };
1000
    })();
1001
    
1002
    // Source: src/methods.js
1003
    
1004
    
1005
    
1006
    // eslint-disable-next-line no-implicit-globals
1007
    var methods = {};
1008
    
1009
    (function($) {
1010
        'use strict';
1011
        var onKeyUp, onPaste, applyToAll;
1012
    
1013
        onKeyUp = function(event) {
1014
            var $el = $(event.target),
1015
                options = $el.data('pwstrength-bootstrap'),
1016
                word = $el.val(),
1017
                userInputs,
1018
                verdictText,
1019
                verdictLevel,
1020
                score;
1021
    
1022
            if (options === undefined) {
1023
                return;
1024
            }
1025
    
1026
            options.instances.errors = [];
1027
            if (word.length === 0) {
1028
                score = undefined;
1029
            } else {
1030
                if (options.common.zxcvbn) {
1031
                    userInputs = [];
1032
                    $.each(
1033
                        options.common.userInputs.concat([
1034
                            options.common.usernameField
1035
                        ]),
1036
                        function(idx, selector) {
1037
                            var value = $(selector).val();
1038
                            if (value) {
1039
                                userInputs.push(value);
1040
                            }
1041
                        }
1042
                    );
1043
                    userInputs = userInputs.concat(options.common.zxcvbnTerms);
1044
                    score = zxcvbn(word, userInputs).guesses;
1045
                    score = Math.log(score) * Math.LOG2E;
1046
                } else {
1047
                    score = rulesEngine.executeRules(options, word);
1048
                }
1049
                if (typeof options.common.onScore === 'function') {
1050
                    score = options.common.onScore(options, word, score);
1051
                }
1052
            }
1053
            ui.updateUI(options, $el, score);
1054
            verdictText = ui.getVerdictAndCssClass(options, score);
1055
            verdictLevel = verdictText[1];
1056
            verdictText = verdictText[0];
1057
    
1058
            if (options.common.debug) {
1059
                console.log(score + ' - ' + verdictText);
0 ignored issues
show
Debugging Code introduced by
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
1060
            }
1061
    
1062
            if (typeof options.common.onKeyUp === 'function') {
1063
                options.common.onKeyUp(event, {
1064
                    score: score,
1065
                    verdictText: verdictText,
1066
                    verdictLevel: verdictLevel
1067
                });
1068
            }
1069
        };
1070
    
1071
        onPaste = function(event) {
1072
            // This handler is necessary because the paste event fires before the
1073
            // content is actually in the input, so we cannot read its value right
1074
            // away. Therefore, the timeouts.
1075
            var $el = $(event.target),
1076
                word = $el.val(),
1077
                tries = 0,
1078
                callback;
1079
    
1080
            callback = function() {
1081
                var newWord = $el.val();
1082
    
1083
                if (newWord !== word) {
1084
                    onKeyUp(event);
1085
                } else if (tries < 3) {
1086
                    tries += 1;
1087
                    setTimeout(callback, 100);
1088
                }
1089
            };
1090
    
1091
            setTimeout(callback, 100);
1092
        };
1093
    
1094
        methods.init = function(settings) {
1095
            this.each(function(idx, el) {
1096
                // Make it deep extend (first param) so it extends also the
1097
                // rules and other inside objects
1098
                var clonedDefaults = $.extend(true, {}, defaultOptions),
1099
                    localOptions = $.extend(true, clonedDefaults, settings),
1100
                    $el = $(el);
1101
    
1102
                localOptions.instances = {};
1103
                $el.data('pwstrength-bootstrap', localOptions);
1104
    
1105
                $.each(localOptions.common.events, function(ignore, eventName) {
1106
                    var handler = eventName === 'paste' ? onPaste : onKeyUp;
1107
                    $el.on(eventName, handler);
1108
                });
1109
    
1110
                ui.initUI(localOptions, $el);
1111
                $el.trigger('keyup');
1112
    
1113
                if (typeof localOptions.common.onLoad === 'function') {
1114
                    localOptions.common.onLoad();
1115
                }
1116
            });
1117
    
1118
            return this;
1119
        };
1120
    
1121
        methods.destroy = function() {
1122
            this.each(function(idx, el) {
1123
                var $el = $(el),
1124
                    options = $el.data('pwstrength-bootstrap'),
1125
                    elements = ui.getUIElements(options, $el);
1126
                elements.$progressbar.remove();
1127
                elements.$verdict.remove();
1128
                elements.$errors.remove();
1129
                $el.removeData('pwstrength-bootstrap');
1130
            });
1131
    
1132
            return this;
1133
        };
1134
    
1135
        methods.forceUpdate = function() {
1136
            this.each(function(idx, el) {
1137
                var event = { target: el };
1138
                onKeyUp(event);
1139
            });
1140
    
1141
            return this;
1142
        };
1143
    
1144
        methods.addRule = function(name, method, score, active) {
1145
            this.each(function(idx, el) {
1146
                var options = $(el).data('pwstrength-bootstrap');
1147
    
1148
                options.rules.activated[name] = active;
1149
                options.rules.scores[name] = score;
1150
                options.rules.extra[name] = method;
1151
            });
1152
    
1153
            return this;
1154
        };
1155
    
1156
        applyToAll = function(rule, prop, value) {
1157
            this.each(function(idx, el) {
1158
                $(el).data('pwstrength-bootstrap').rules[prop][rule] = value;
1159
            });
1160
        };
1161
    
1162
        methods.changeScore = function(rule, score) {
1163
            applyToAll.call(this, rule, 'scores', score);
1164
    
1165
            return this;
1166
        };
1167
    
1168
        methods.ruleActive = function(rule, active) {
1169
            applyToAll.call(this, rule, 'activated', active);
1170
    
1171
            return this;
1172
        };
1173
    
1174
        methods.ruleIsMet = function(rule) {
1175
            var rulesMetCnt = 0;
1176
    
1177
            if (rule === 'wordMinLength') {
1178
                rule = 'wordMinLengthStaticScore';
1179
            } else if (rule === 'wordMaxLength') {
1180
                rule = 'wordMaxLengthStaticScore';
1181
            }
1182
    
1183
            this.each(function(idx, el) {
1184
                var options = $(el).data('pwstrength-bootstrap'),
1185
                    ruleFunction = rulesEngine.validation[rule],
1186
                    result;
1187
    
1188
                if (typeof ruleFunction !== 'function') {
1189
                    ruleFunction = options.rules.extra[rule];
1190
                }
1191
                if (typeof ruleFunction === 'function') {
1192
                    result = ruleFunction(options, $(el).val(), 1);
1193
                    if ($.isNumeric(result)) {
1194
                        rulesMetCnt += result;
1195
                    }
1196
                }
1197
            });
1198
    
1199
            return rulesMetCnt === this.length;
1200
        };
1201
    
1202
        $.fn.pwstrength = function(method) {
1203
            var result;
1204
    
1205
            if (methods[method]) {
1206
                result = methods[method].apply(
1207
                    this,
1208
                    Array.prototype.slice.call(arguments, 1)
1209
                );
1210
            } else if (typeof method === 'object' || !method) {
1211
                result = methods.init.apply(this, arguments);
1212
            } else {
1213
                $.error(
1214
                    'Method ' +
1215
                        method +
1216
                        ' does not exist on jQuery.pwstrength-bootstrap'
1217
                );
1218
            }
1219
    
1220
            return result;
0 ignored issues
show
Bug introduced by
The variable result seems to not be initialized for all possible execution paths.
Loading history...
1221
        };
1222
    })(jQuery);
1223
    }(jQuery));