summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--node_modules/passwdqc/src/passwdqc_check.js492
1 files changed, 0 insertions, 492 deletions
diff --git a/node_modules/passwdqc/src/passwdqc_check.js b/node_modules/passwdqc/src/passwdqc_check.js
deleted file mode 100644
index 913bcc008..000000000
--- a/node_modules/passwdqc/src/passwdqc_check.js
+++ /dev/null
@@ -1,492 +0,0 @@
-/*
- * Copyright (c) 2000-2002,2010,2013 by Solar Designer. See LICENSE.
- * Copyright (c) 2014 Parallels, Inc.
- */
-({define:typeof define!="undefined"?define:function(deps, factory){module.exports = factory(exports, require("./dictionary"));}}).
-define(["exports", "./dictionary"], function(exports, dict){
- var dictionary = dict.dictionary;
-
- var FIXED_BITS = 15;
-
- /*
- * Calculates the expected number of different characters for a random
- * password of a given length. The result is rounded down. We use this
- * with the _requested_ minimum length (so longer passwords don't have
- * to meet this strict requirement for their length).
- */
- function expected_different(charset, length){
- var x, y, z;
-
- x = ((charset - 1) << FIXED_BITS) / charset;
- y = x;
- while (--length > 0)
- y = (y * x) >> FIXED_BITS;
- z = charset * ((1 << FIXED_BITS) - y);
-
- return (z >> FIXED_BITS)|0;
- }
-
- /*
- * A password is too simple if it is too short for its class, or doesn't
- * contain enough different characters for its class, or doesn't contain
- * enough words for a passphrase.
- *
- * The biases are added to the length, and they may be positive or negative.
- * The passphrase length check uses passphrase_bias instead of bias so that
- * zero may be passed for this parameter when the (other) bias is non-zero
- * because of a dictionary word, which is perfectly normal for a passphrase.
- * The biases do not affect the number of different characters, character
- * classes, and word count.
- */
- function is_simple(params, newpass, bias, passphrase_bias){
- var length, classes, words, chars,
- digits, lowers, uppers, others, unknowns,
- c, p;
-
- length = classes = words = chars = 0;
- digits = lowers = uppers = others = unknowns = 0;
- p = ' ';
- while (c = newpass[length]) {
- length++;
-
- if (!isascii(c))
- unknowns++;
- else if (isdigit(c))
- digits++;
- else if (islower(c))
- lowers++;
- else if (isupper(c))
- uppers++;
- else
- others++;
- /* A word starts when a letter follows a non-letter or when a non-ASCII
- * character follows a space character. We treat all non-ASCII characters
- * as non-spaces, which is not entirely correct (there's the non-breaking
- * space character at 0xa0, 0x9a, or 0xff), but it should not hurt. */
- if (isascii(p)) {
- if (isascii(c)) {
- if (isalpha(c) && !isalpha(p))
- words++;
- } else if (isspace(p))
- words++;
- }
- p = c;
-
- /* Count this character just once: when we're not going to see it anymore */
- if(newpass.slice(length).indexOf(c) === -1)
- chars++;
- }
-
- length = strlen(newpass);
-
- if (!length)
- return 1;
-
- /* Upper case characters and digits used in common ways don't increase the
- * strength of a password */
- c = newpass[0];
- if (uppers && isascii(c) && isupper(c))
- uppers--;
- c = newpass[length - 1];
- if (digits && isascii(c) && isdigit(c))
- digits--;
-
- /* Count the number of different character classes we've seen. We assume
- * that there are no non-ASCII characters for digits. */
- classes = 0;
- if (digits)
- classes++;
- if (lowers)
- classes++;
- if (uppers)
- classes++;
- if (others)
- classes++;
- if (unknowns && classes <= 1 && (!classes || digits || words >= 2))
- classes++;
-
- for (var min = params.min; classes > 0; classes--)
- switch (classes) {
- case 1:
- if (length + bias >= min[0] &&
- chars >= expected_different(10, min[0]) - 1)
- return 0;
- return 1;
-
- case 2:
- if (length + bias >= min[1] &&
- chars >= expected_different(36, min[1]) - 1)
- return 0;
- if (!params.passphrase_words ||
- words < params.passphrase_words)
- continue;
- if (length + passphrase_bias >= min[2] &&
- chars >= expected_different(27, min[2]) - 1)
- return 0;
- continue;
-
- case 3:
- if (length + bias >= min[3] &&
- chars >= expected_different(62, min[3]) - 1)
- return 0;
- continue;
-
- case 4:
- if (length + bias >= min[4] &&
- chars >= expected_different(95, min[4]) - 1)
- return 0;
- continue;
- }
-
- return 1;
- }
-
- function unify(dst, src){
- for (var i = 0; i < src.length; i++){
- var c = src.charAt(i);
- if (isascii(c) && isupper(c))
- c = c.toLowerCase();
- switch (c) {
- case 'a': case '@':
- c = '4'; break;
- case 'e':
- c = '3'; break;
- /* Unfortunately, if we translate both 'i' and 'l' to '1', this would
- * associate these two letters with each other - e.g., "mile" would
- * match "MLLE", which is undesired. To solve this, we'd need to test
- * different translations separately, which is not implemented yet. */
- case 'i': case '|':
- c = '!'; break;
- case 'l':
- c = '1'; break;
- case 'o':
- c = '0'; break;
- case 's': case '$':
- c = '5'; break;
- case 't': case '+':
- c = '7'; break;
- }
- dst += c;
- }
-
- return dst;
- }
-
- function reverse(src){
- return src.split("").reverse().join("");
- }
-
- /*
- * Needle is based on haystack if both contain a long enough common
- * substring and needle would be too simple for a password with the
- * substring either removed with partial length credit for it added
- * or partially discounted for the purpose of the length check.
- */
- function is_based(params, haystack, needle, original, mode){
- var scratch, length, i, j, p, worst_bias;
-
- if (!params.match_length) // disabled
- return 0;
-
- if (params.match_length < 0) // misconfigured
- return 1;
-
- scratch = null;
- worst_bias = 0;
-
- length = needle.length;
- for (i = 0; i <= length - params.match_length; i++)
- for (j = params.match_length; i + j <= length; j++) {
- var bias = 0, j1 = j - 1;
- var q0 = needle[i], q1 = needle.slice(i+1);
-
- for (var k=0; k<haystack.length; k++)
- if (haystack[k] == q0 && haystack.substring(k+1, k+1+j1) == q1.substring(0,j1)) { // or memcmp()
- if ((mode & 0xff) == 0) { // remove & credit
- // remove j chars
- var pos = length - (i + j);
- if (!(mode & 0x100)) // not reversed
- pos = i;
-
- scratch = original.substring(0, pos) + original.substring(pos+j);
-
- // add credit for match_length - 1 chars
- bias = params.match_length - 1;
- if (is_simple(params, scratch, bias, bias))
- return 1;
- } else { // discount
- // Require a 1 character longer match for substrings containing leetspeak
- // when matching against dictionary words
- bias = -1;
- if ((mode & 0xff) == 1) { // words
- var pos = i, end = i + j;
- if (mode & 0x100) { // reversed
- pos = length - end;
- end = length - i;
- }
- for (; pos < end; pos++)
- if (!isalpha(original[pos])) {
- if (j == params.match_length){
- var cnt = true;
- break;
- }
- bias = 0;
- break;
- }
- if(cnt){
- cnt = false;
- continue;
- }
- }
-
- // discount j - (match_length + bias) chars
- bias += params.match_length - j;
- // bias <= -1
- if (bias < worst_bias) {
- if (is_simple(params, original, bias,
- (mode & 0xff) == 1 ? 0 : bias))
- return 1;
- worst_bias = bias;
- }
- }
- }
-
- // Zero bias implies that there were no matches for this length. If so,
- // * there's no reason to try the next substring length (it would result in
- // * no matches as well). We break out of the substring length loop and
- // * proceed with all substring lengths for the next position in needle.
- if (!bias)
- break;
- }
-
- return 0;
- }
-
- /*
- * Common sequences of characters.
- * We don't need to list any of the entire strings in reverse order because the
- * code checks the new password in both "unified" and "unified and reversed"
- * form against these strings (unifying them first indeed). We also don't have
- * to include common repeats of characters (e.g., "777", "!!!", "1000") because
- * these are often taken care of by the requirement on the number of different
- * characters.
- */
- var seq = [
- "0123456789",
- "`1234567890-=",
- "~!@#$%^&*()_+",
- "abcdefghijklmnopqrstuvwxyz",
- "a1b2c3d4e5f6g7h8i9j0",
- "1a2b3c4d5e6f7g8h9i0j",
- "abc123",
- "qwertyuiop[]\\asdfghjkl;'zxcvbnm,./",
- "qwertyuiop{}|asdfghjkl:\"zxcvbnm<>?",
- "qwertyuiopasdfghjklzxcvbnm",
- "1qaz2wsx3edc4rfv5tgb6yhn7ujm8ik,9ol.0p;/-['=]\\",
- "!qaz@wsx#edc$rfv%tgb^yhn&ujm*ik<(ol>)p:?_{\"+}|",
- "qazwsxedcrfvtgbyhnujmikolp",
- "1q2w3e4r5t6y7u8i9o0p-[=]",
- "q1w2e3r4t5y6u7i8o9p0[-]=\\",
- "1qaz1qaz",
- "1qaz!qaz", /* can't unify '1' and '!' - see comment in unify() */
- "1qazzaq1",
- "zaq!1qaz",
- "zaq!2wsx"
- ];
-
- /*
- * This wordlist check is now the least important given the checks above
- * and the support for passphrases (which are based on dictionary words,
- * and checked by other means). It is still useful to trap simple short
- * passwords (if short passwords are allowed) that are word-based, but
- * passed the other checks due to uncommon capitalization, digits, and
- * special characters. We (mis)use the same set of words that are used
- * to generate random passwords. This list is much smaller than those
- * used for password crackers, and it doesn't contain common passwords
- * that aren't short English words. Perhaps support for large wordlists
- * should still be added, even though this is now of little importance.
- */
- function is_word_based(params, needle, original, is_reversed){
- var word, unified, i, length, mode;
-
- if (!params.match_length) /* disabled */
- return null;
-
- mode = is_reversed | 1;
- word = "";
- for (i = 0; i < 0x1000; i++) {
- word = dictionary[i];
- length = strlen(word);
- if (length < params.match_length)
- continue;
-
- word = unify("", word);
- if (is_based(params, word, needle, original, mode))
- return REASON_WORD;
- }
-
- mode = is_reversed | 2;
- for (i = 0; i < seq.length; i++) {
- unified = unify("", seq[i]);
- if (!unified)
- return REASON_ERROR;
- if (is_based(params, unified, needle, original, mode))
- return REASON_SEQ;
- }
-
- if (params.match_length <= 4)
- for (i = 1900; i <= 2039; i++) {
- if (is_based(params, i.toString(), needle, original, mode))
- return REASON_SEQ;
- }
-
- return null;
- }
-
- function passwdqc_check(params, newpass, oldpass, pw){
- var truncated, u_newpass, u_reversed, u_oldpass,
- u_name, u_gecos, u_dir, reason, length;
-
- u_newpass = u_reversed = null;
- u_oldpass = null;
- u_name = u_gecos = u_dir = null;
-
- reason = REASON_ERROR;
-
- if (oldpass && oldpass == newpass)
- return REASON_SAME;
-
- length = strlen(newpass);
-
- if (length < params.min[4])
- return REASON_SHORT;
-
- if (length > params.max) {
- if (params.max == 8) {
- truncated = newpass.substr(0, 8);
- newpass = truncated;
- if (oldpass && !oldpass.substr(0, 8) !== newpass.substr(0, 8))
- return REASON_SAME;
- } else {
- return REASON_LONG;
- }
- }
-
- if (is_simple(params, newpass, 0, 0)) {
- reason = REASON_SIMPLE;
- if (length < params.min[1] && params.min[1] <= params.max)
- reason = REASON_SIMPLESHORT;
- return reason;
- }
-
- if (!(u_newpass = unify("", newpass)))
- return reason; /* REASON_ERROR */
- if (!(u_reversed = reverse(u_newpass)))
- return reason;
- if (oldpass && !(u_oldpass = unify("", oldpass)))
- return reason;
- if (pw) {
- if (!(u_name = unify("", pw.pw_name)) ||
- !(u_gecos = unify("", pw.pw_gecos)) ||
- !(u_dir = unify("", pw.pw_dir)))
- return reason;
- }
-
- if (oldpass && params.similar_deny &&
- (is_based(params, u_oldpass, u_newpass, newpass, 0) ||
- is_based(params, u_oldpass, u_reversed, newpass, 0x100)))
- return REASON_SIMILAR;
-
- if (pw &&
- (is_based(params, u_name, u_newpass, newpass, 0) ||
- is_based(params, u_name, u_reversed, newpass, 0x100) ||
- is_based(params, u_gecos, u_newpass, newpass, 0) ||
- is_based(params, u_gecos, u_reversed, newpass, 0x100) ||
- is_based(params, u_dir, u_newpass, newpass, 0) ||
- is_based(params, u_dir, u_reversed, newpass, 0x100)))
- return REASON_PERSONAL;
-
- reason = is_word_based(params, u_newpass, newpass, 0);
- if (!reason)
- reason = is_word_based(params, u_reversed, newpass, 0x100);
-
- return reason;
- }
-
- function isascii(c){
- return /^[\x00-\x7F]?$/.test(c);
- }
-
- function isdigit(c){
- return /^\d?$/.test(c);
- }
-
- function islower(c){
- return isalpha(c) && c.toLowerCase() === c;
- }
-
- function isupper(c){
- return isalpha(c) && c.toUpperCase() === c;
- }
-
- function isalpha(c){
- return /^\w?$/.test(c) && c != '_' && /^\D?$/.test(c);
- }
-
- function isspace(c){
- return /^\s?$/.test(c);
- }
-
- function strlen(str){
- var length = str.length, count = 0, ch = 0;
- for(var i=0; i < length; i++){
- ch = str.charCodeAt(i);
- if(ch <= 127){
- count++;
- }else if(ch <= 2047){
- count += 2;
- }else if(ch <= 65535){
- count += 3;
- }else if(ch <= 2097151){
- count += 4;
- }else if(ch <= 67108863){
- count += 5;
- }else{
- count += 6;
- }
- }
-
- return count;
- }
-
- var REASON_ERROR = "check failed",
- REASON_SAME = "is the same as the old one",
- REASON_SIMILAR = "is based on the old one",
- REASON_SHORT = "too short",
- REASON_LONG = "too long",
- REASON_SIMPLESHORT = "not enough different characters or classes for this length",
- REASON_SIMPLE = "not enough different characters or classes",
- REASON_PERSONAL = "based on personal login information",
- REASON_WORD = "based on a dictionary word and not a passphrase",
- REASON_SEQ = "based on a common sequence of characters and not a passphrase",
- INT_MAX = 2147483647;
-
- var params = {
- min: [INT_MAX, 24, 11, 8, 7],
- max: 40,
- passphrase_words: 3,
- match_length: 4,
- similar_deny: 1,
- random_bits: 47,
- flags: 3,
- retry: 3
- }
-
- function check(newpass, oldpass, login, gecos, pms){
- return passwdqc_check(pms || params, newpass, oldpass, login ? { pw_name: login, pw_gecos: gecos } : login);
- }
-
- exports.check = check;
-
- return exports;
-}); \ No newline at end of file