PageSourceSearch

https://rental.worldlibrary.co.jp/wp-content/themes/rental/js/lib/password-strength.js?ver=7.1.2

js worldlibrary.co.jp collected 2026-10-04 13:26:02 UTC 18,419 bytes, 569 lines download raw bytes

1/**
2 * This is an object oriented approach of rumkin.com/passchk.js
3 * Originally written to be self contained, this makes it as an object
4 * that can be instantiated.
5 */
6"use strict";
7
8// fid-umd {"name":"PasswordStrength"}
9(function (name, root, factory) {
10    /**
11     * Determines if something is an object. Use for minification.
12     *
13     * @param {*} x
14     * @return {boolean}
15     */
16    function isObject(x) {
17        return typeof x === "object";
18    }
19
20    if ((typeof module)[0] === "o" && isObject(module.exports)) {
21        module.exports = factory();
22    } else if ((typeof exports)[0] === "o") {
23        exports[name] = factory();
24    } else if (isObject(root.define) && root.define.amd) {
25        root.define(name, [], factory);
26    } else if (isObject(root.modulejs)) {
27        root.modulejs.define(name, factory);
28    } else if (isObject(root.YUI)) {
29        root.YUI.add(name, function (Y) {
30            Y[name] = factory();
31        });
32    } else {
33        root[name] = factory();
34    }
35
36    // eslint-disable-next-line
37}("PasswordStrength", this, function () {
38    // fid-umd end
39
40    /**
41     * Shim the Math object to support log2 if it does not already.
42     */
43    if (!Math.log2) {
44        /**
45         * You can emulate any log in any base with log.
46         *
47         * @param {number} n
48         * @return {number}
49         */
50        Math.log2 = function (n) {
51            return Math.log(n) / Math.log(2);
52        };
53    }
54
55
56    /**
57     * Iterates over an object
58     *
59     * @param {Object} obj
60     * @param {Function} callback(key,value)
61     */
62    function objectForEach(obj, callback) {
63        Object.keys(obj).forEach(function (key) {
64            callback(key, obj[key]);
65        });
66    }
67
68
69    /**
70     * Turns a list of characters into a regular expression that will match
71     * whatever you pass in.  There may be trouble generating the pattern,
72     * so here we are escaping every character that isn't alphanumeric.
73     *
74     * @param {string} letters
75     * @param {string} flags (defaults to "")
76     * @return {RegExp} pattern
77     */
78    function safeCharMatcher(letters, flags) {
79        var pattern;
80
81        pattern = letters.replace(/[\W_]/g, function (x) {
82            return "\\" + x;
83        });
84        pattern = "[" + pattern + "]";
85
86        return new RegExp(pattern, flags || "");
87    }
88
89
90    /**
91     * Determine the strength of a password.
92     *
93     * Usage:
94     *
95     *     ps = new PasswordStrength();
96     *
97     *     // Improve checks by adding additional data files - optional
98     *     ps.addCommonPasswords(pass);  // data/common-passwords.json
99     *     ps.addTrigraphMap(tri);  // data/trigraphs.json
100     *
101     *     // Calculate password strength
102     *     stats = ps.check("my password");
103     *
104     * @return {PasswordStrength} instance
105     */
106    function PasswordStrength() {
107        if (!(this instanceof PasswordStrength)) {
108            return new PasswordStrength();
109        }
110
111        this.commonPasswords = null;
112        this.trigraph = null;
113        this.charsets = {
114            number: "0123456789",
115            lower: "abcdefghijklmnopqrstuvwxyz",
116            upper: "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
117
118            // Things found in sentences
119            punctuation: "!'.,:;?&-\" ",
120
121            // Typically math-related
122            symbol: "@#$%^*(){}[]><~`_+=|/"
123        };
124
125
126        /**
127         * Sets commonPassword property with what a user passes in.
128         * Uses it if it's an array, processes it into an array if it's a
129         * string and throws an error if it's not a format we can work with.
130         *
131         * Returns the PasswordCheck object so it can be chained
132         *
133         * @param {(Array|string)} passwords
134         * @return {PasswordStrength} PasswordStrength
135         */
136        this.addCommonPasswords = function (passwords) {
137            if (passwords) {
138                if (Array.isArray(passwords)) {
139                    this.commonPasswords = passwords;
140                } else if (typeof passwords === "string") {
141                    this.commonPasswords = passwords.split(/\r\n|\r|\n/);
142                } else {
143                    throw new Error("Format does not match any expected format.");
144                }
145            } else {
146                this.commonPasswords = [];
147            }
148
149            return this;
150        };
151
152
153        /**
154         * TrigraphMap is an ojbect representing entries of 3 letter
155         * combinations and how often they appear.
156         *
157         * {
158         *     "_ty": 123,
159         *     "tyl": 22,
160         *     "yle": 19,
161         *     "ler": 5,
162         *     "er_": 543
163         * }
164         *
165         * For further explanation on the numbers, check out the documentation
166         * in the data folder.
167         *
168         * @typedef {Object} PasswordStrength~trigraphMap
169         * @property {number} * Frequencies of that letter combo.
170         */
171
172        /**
173         * Returns the PasswordStrength object so it can be chained
174         *
175         * @param {PasswordStrength~trigraphMap} trigraphMap
176         * @return {PasswordStrength} PasswordStrength
177         */
178        this.addTrigraphMap = function (trigraphMap) {
179            if (trigraphMap) {
180                if (trigraphMap && typeof trigraphMap === "object" && !Array.isArray(trigraphMap)) {
181                    this.trigraph = trigraphMap;
182                } else {
183                    throw new Error("Format does not match any expected format.");
184                }
185            } else {
186                this.trigraph = null;
187            }
188
189            return this;
190        };
191
192
193        /**
194         * charsetGroups is an object of different group of defined characters
195         * used in figuring out how many characters per group as well as
196         * what characters fall into each group.  It is based on a
197         * PasswordStrength instance's `this.charsets` object.  When a password
198         * has a character that matches one of the character sets in the
199         * PasswordStrength instance's sets, this sets that key to `true`.
200         *
201         * The "other" key is all letters that did not match another set.
202         *
203         * Example for the password "abcd£1234":
204         *
205         * {
206         *     lower: true,
207         *     upper: false,
208         *     number: true,
209         *     punctuation: false,
210         *     symbol: false,
211         *     other: "£"
212         * }
213         *
214         * @typedef {Object} PasswordStrength~charsetGroups
215         * @property {string} other Characters that did not match another set
216         * @property {boolean} * All of the rest of the sets just set flags
217         */
218
219        /**
220         * Gets the character set size of the current password.
221         * This breaks up the each character set and tests the password
222         * to see which set they belong in.
223         *
224         * @param {string} passToCheck
225         * @return {PasswordStrength~charsetGroups} groups
226         */
227        this.charsetGroups = function (passToCheck) {
228            var groups;
229
230            groups = {};
231            objectForEach(this.charsets, function (key, value) {
232                groups[key] = safeCharMatcher(value).test(passToCheck);
233            });
234            groups.other = this.otherChars(passToCheck);
235
236            return groups;
237        };
238
239
240        /**
241         * Calculates the size of each flag found for a password,
242         * and will get the flags if a password was passed in.
243         *
244         * @param {PasswordStrength~charsetGroups} groups
245         * @return {number} result
246         */
247        this.charsetSize = function (groups) {
248            var size;
249
250            size = 0;
251
252            objectForEach(this.charsets, function (key, value) {
253                if (groups[key]) {
254                    size += value.length;
255                }
256            });
257
258            if (typeof groups.other === "string") {
259                size += groups.other.length;
260            }
261
262            return size;
263        };
264
265        /**
266         * Statistics is an object with information about the current state of
267         * the password.
268         *
269         * @typedef {Object} PasswordStrength~statistics
270         * @property {number} charsetSize size of the characters from each group the characters fall into.
271         * @property {boolean} commonPassword
272         * @property {number} passwordLength the length of the current password
273         * @property {number} shannonEntropyBits
274         * @property {string} strength estimates strength score for the password
275         * @property {(null|number)} trigraphEntropyBits
276        */
277
278        /**
279         * Calculates a bunch of statistics about a given password.
280         *
281         * @param {string} currentPassword
282         * @return {PasswordStrength~statistics}
283         */
284        this.check = function (currentPassword) {
285            var result;
286
287            result = {
288                charsetSize: 0,
289                commonPassword: false,
290                nistEntropyBits: 0,
291                passwordLength: 0,
292                shannonEntropyBits: 0,
293                strengthCode: null,
294                trigraphEntropyBits: null,
295                charsets: null
296            };
297
298            // For undefined and if we get an empty value
299            if (!currentPassword || !currentPassword.length) {
300                if (this.trigraph) {
301                    result.trigraphEntropyBits = 0;
302                }
303
304                return result;
305            }
306
307            result.commonPassword = this.checkCommonPasswords(currentPassword);
308            result.charsets = this.charsetGroups(currentPassword);
309            result.charsetSize = this.charsetSize(result.charsets);
310            result.nistEntropyBits = this.nistScore(currentPassword);
311            result.shannonEntropyBits = this.shannonScore(currentPassword);
312            result.passwordLength = currentPassword.length;
313            result.trigraphEntropyBits = this.checkTrigraph(currentPassword, result.charsetSize);
314            result.strengthCode = this.determineStrength(result);
315
316            return result;
317        };
318
319        /**
320         * This checks to see if the password is in the common list of
321         * passwords.  If in the common passwords lists, sets the warn flag.
322         *
323         * @param {string} passToCheck
324         * @return {boolean}
325         */
326        this.checkCommonPasswords = function (passToCheck) {
327            var commonPasswordsLength, commonPasswordsList, i;
328
329            passToCheck = passToCheck.toLowerCase();
330
331            if (this.commonPasswords && this.commonPasswords.length) {
332                commonPasswordsList = this.commonPasswords;
333                commonPasswordsLength = this.commonPasswords.length;
334
335                for (i = 0; i < commonPasswordsLength; i += 1) {
336                    if (commonPasswordsList[i] === passToCheck) {
337                        return true;
338                    }
339                }
340
341                return false;
342            }
343
344            return null;
345        };
346
347
348        /**
349         * Compares the password to the trigraph to get the rating of how
350         * guessable the password is.
351         *
352         * @param {string} passToCheck
353         * @param {number} charsetSize
354         * @return {number} entropy in bits
355         */
356        this.checkTrigraph = function (passToCheck, charsetSize) {
357            var i, score, str;
358
359            if (!this.trigraph) {
360                return null;
361            }
362
363            score = 1;
364            passToCheck = passToCheck.toLowerCase().replace(/[\W_]/gi, " ").trim();
365            passToCheck = "_" + passToCheck + "_";
366
367            for (i = 0; i < passToCheck.length - 2; i += 1) {
368                str = passToCheck.substr(i, 3);
369
370                if (this.trigraph[str]) {
371                    // Less than fully random
372                    score *= (1.0 - this.trigraph[str] / 10000) * charsetSize;
373                } else {
374                    // Fully random selection
375                    score *= charsetSize;
376                }
377            }
378
379            return Math.log2(score);
380        };
381
382
383        /**
384         * Takes parameters and calculates the strength of a given password
385         * from a list of codes set. This will use the trigraph entropy bits if
386         * available and fallback to the shannon entropy bits which we should
387         * always have.
388         *
389         * @param {Object} status
390         * @return {string} strengthCode
391         */
392        this.determineStrength = function (status) {
393            var entropyBits, strengthCode;
394
395            strengthCode = "";
396
397            if (status.trigraphEntropyBits) {
398                entropyBits = status.trigraphEntropyBits;
399            } else {
400                entropyBits = status.shannonEntropyBits;
401            }
402
403            if (entropyBits <= 32) {
404                // Keep out a typical attacker for minutes
405                strengthCode = "VERY_WEAK";
406            } else if (entropyBits <= 48) {
407                // Crackable by a typical home computer in a week.
408                strengthCode = "WEAK";
409            } else if (entropyBits <= 64) {
410                // A specialized computer could get this in one year.
411                strengthCode = "REASONABLE";
412            } else if (entropyBits <= 80) {
413                // Resistant to a large, coordinated attack (botnet) for over a year.
414                strengthCode = "STRONG";
415            } else {
416                // Nearly impossible to brute force, given more than all of the
417                // computing power in the world, optimized algorithms,
418                // specialized hardware and a thousand years.
419                strengthCode = "VERY_STRONG";
420            }
421
422            return strengthCode;
423        };
424
425
426        /**
427         * Calculates the NIST score based on the following rules from NIST
428         * Special Publication 800-63 as of June 2004.
429         *
430         * * The entropy of the first character is four bits;
431         * * The entropy of the next seven characters are two bits per
432         *   character;
433         * * The ninth through the twentieth character has 1.5 bits of
434         *   entropy per character;
435         * * Characters 21 and above have one bit of entropy per character.
436         * * A "bonus" of six bits is added if both upper case letters and
437         *   non-alphabetic characters are used.
438         * * A "bonus" of six bits is added for passwords of length 1 through
439         *   19 characters following an extensive dictionary check to ensure
440         *   the password is not contained within a large dictionary.
441         *   Passwords of 20 characters or more do not receive this bonus
442         *   because it is assumed they are pass-phrases consisting of
443         *   multiple dictionary words.
444         *
445         * According to Wikipedia, this score might not be overly useful.
446         *
447         * > Later research into human-selected password entropy using newly
448         * > available real world data has demonstrated that the NIST scheme
449         * > does not provide a valid metric for entropy estimation of
450         * > human-selected passwords.
451         *
452         * @param {string} password
453         * @return {number}
454         */
455        this.nistScore = function (password) {
456            var len, score;
457
458            len = password.length;
459            score = 0;
460
461            if (len > 20) {
462                score += len - 20;
463                len = 20;
464            }
465
466            if (len > 8) {
467                score += 1.5 * (len - 8);
468                len = 8;
469            }
470
471            if (len > 1) {
472                score += 2 * (len - 1);
473                len = 1;
474            }
475
476            if (len) {
477                score += 4;
478            }
479
480            if (password.match(/[A-Z]/) && password.match(/[^A-Za-z]/)) {
481                score += 6;
482            }
483
484            // Don't have a large dictionary, thus nobody gets the 6 bit
485            // bonus.
486            return score;
487        };
488
489
490        /**
491         * Calls function to see if there are other characters used
492         * which we don't explicitly check for.
493         *
494         * @param {string} passToCheck
495         * @return {string} result
496         */
497        this.otherChars = function (passToCheck) {
498            var chars, hash, pattern;
499
500            chars = "";
501            objectForEach(this.charsets, function (key, value) {
502                chars += value;
503            });
504            pattern = safeCharMatcher(chars, "g");
505            hash = {};
506            passToCheck.replace(pattern, "").split("").forEach(function (letter) {
507                hash[letter] = true;
508            });
509
510            return Object.keys(hash).join("");
511        };
512
513
514        /**
515         * Calculate the Shannon Entropy value of a password.  This is really
516         * the number of bits necessary to represent the possible characters
517         * times the length of the password.
518         *
519         * Reworked from code under a MIT license.
520         * entropy.js MIT License © 2014 James Abney http://github.com/jabney
521         *
522         * @param {string} pass Password to evaluate
523         * @return {number} Bits of entropy
524         */
525        this.shannonScore = function (pass) {
526            var freq, passLength, sum;
527
528            /**
529             * Counts how often each character appears in the passphrase.
530             *
531             * @return {Object} Treated like a hash, indexed by the character.
532             */
533            function countFrequencies() {
534                var c, h, i;
535
536                // Hash for collecting frequencies
537                h = {};
538
539                for (i = 0; i < passLength; i += 1) {
540                    c = pass.charAt(i);
541
542                    if (h[c]) {
543                        h[c] += 1;
544                    } else {
545                        h[c] = 1;
546                    }
547                }
548
549                return h;
550            }
551
552            sum = 0;
553            passLength = pass.length;
554            freq = countFrequencies();
555            objectForEach(freq, function (key, value) {
556                var score;
557
558                score = value / passLength;
559                sum -= score * Math.log2(score);
560            });
561
562            return sum * passLength;
563        };
564    }
565
566    return PasswordStrength;
567    // fid-umd post
568}));
569// fid-umd post-end

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.