Javascript密码生成器添加空格和失败的测试

时间:2016-04-19 10:36:51

标签: javascript passwords password-generator window.crypto

我正在尝试构建一个密码生成器,用于创建符合以下内容的密码:

  
      
  1. 最少8个字符,最多40个字符
  2.   
  3. 必须至少包含1个大写,小写,数字和符号
  4.   

我正在避免选择Math.random,我更喜欢加密选项。

我已经阅读了很多篇文章试图让它工作,但我遇到了以下问题:

  
      
  1. 输出字符串中似乎出现了随机空格,通常在最后。

  2.   
  3. 输出值有时不符合min 8 char规则。

  4.   

我意识到我可能有太多额外的if语句双重检查,但我很难看到它出错的地方。

这是进入另一个系统,所以我创建它尽可能模块化和功能。对于下面的大型片段道歉,我无法在jsfiddle.

中使用它
function cryptoPassword(){

    var minFieldNum = 8;    //Minimum char size of desired output
    var maxFieldNum = 40;   //X defines their fields as 40 as the max_length    
    var outputValue = '';   //Output for field/overall function

    var fieldRandom = getRandomInt(minFieldNum, maxFieldNum); //Generate length of password 

    if (fieldRandom < minFieldNum || fieldRandom > maxFieldNum) {
    fieldRandom = getRandomInt(minFieldNum, maxFieldNum); //Regenerate if length doesn't conform - Not working? 
    }
    else {
        for (i = 0; outputValue.length < fieldRandom; i++) {
             var mask = getRandomMask(); //Get mask selection 
             var randomChar = mask.charAt(getRandomInt(0,mask.length)); //Pick random char in mask
             if (randomChar == " ") { //I don't know where the spaces come from
                var randomChar = mask.charAt(getRandomInt(0,mask.length)); //Pick random char in mask
            }
            outputValue += randomChar; //Add to output
        }

        if (passwordChecker(outputValue, minFieldNum)) {
            return outputValue + " " + passwordChecker(outputValue, minFieldNum);
        }
        else {
            return cryptoPassword();
        }

    }
}


function getRandomInt(min, max) {  
    var byteArray = new Uint8Array(1);  
    window.crypto.getRandomValues(byteArray);
    var range = (max - min + 1);
    return min  + (byteArray[0] % range);
}

function getRandomMask() {
    var maskLcaseChar = 'abcdefghijklmnopqrstuvwxyz';
    var maskUcaseChar = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    var maskNumeric = '0123456789';
    var maskSpecial = '!"$%^&*(){}[];#,./:@~<>?|_+-='; 

    var maskRandomNo = getRandomInt(0, 3);
    var selectMask = [maskLcaseChar, maskUcaseChar, maskNumeric, maskSpecial];  
    return  selectMask[maskRandomNo];
}

function passwordChecker(output, minSize){
    var checkChars = '!"$%^&*(){}[];#,./:@~<>?|_+-='; 
    if (output.length < minSize){
        return false
    }
    else if((output.toUpperCase() != output) && (output.toLowerCase() != output)) {
        for (var i = 0; i < output.length; i++) {
            if (checkChars.indexOf(output.charAt(i)) != -1) {
                return true;
            }
        }
    }
    return false;
}

1 个答案:

答案 0 :(得分:0)

所以问题似乎与getRandomInt函数有关,它会在0和掩码长度之间返回一个int。当你处理数组时,你真的希望它在0和数组-1的长度之间。

你正在从charAt函数返回空字符串,因为你要求在数组旁边放置一个位置。

我已经解决了这个问题并且还优化了生成部分。它总是从每个掩码中添加一个char,然后在其后随机获取它们。然后我将字符串洗牌,移动最初的4个。它不是使用加密来进行洗牌,但我不认为那是必要的。

function cryptoPassword(){

    var maskLcaseChar = 'abcdefghijklmnopqrstuvwxyz';
    var maskUcaseChar = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    var maskNumeric = '0123456789';
    var maskSpecial = '!"$%^&*(){}[];#,./:@~<>?|_+-=';
    var maskAll = maskLcaseChar + maskUcaseChar + maskNumeric + maskSpecial;
    var mask = '';

    var minFieldNum = 8;    //Minimum char size of desired output
    var maxFieldNum = 40;   //X defines their fields as 40 as the max_length
    var outputValue = '';   //Output for field/overall function

    var fieldRandom = getRandomInt(minFieldNum, maxFieldNum); //Generate length of password

    if (fieldRandom < minFieldNum || fieldRandom > maxFieldNum) {
        console.log("error length", fieldRandom)
        fieldRandom = getRandomInt(minFieldNum, maxFieldNum); //Regenerate if length doesn't conform - Not working?

    }
    else {
        var randomChar = '';
        var rnd;
        randomChar = maskLcaseChar.charAt(getRandomInt(0,maskLcaseChar.length)); //Pick random lower case
        outputValue += randomChar; //Add to output
        randomChar = maskUcaseChar.charAt(getRandomInt(0,maskUcaseChar.length)); //Pick random upper case
        outputValue += randomChar; //Add to output
        randomChar = maskNumeric.charAt(getRandomInt(0,maskNumeric.length)); //Pick random numeric
        outputValue += randomChar; //Add to output
        randomChar = maskSpecial.charAt(getRandomInt(0,maskSpecial.length)); //Pick random special
        outputValue += randomChar; //Add to output
        mask = maskAll;
        for (var i = 3; i < fieldRandom; i++) {
            randomChar = mask.charAt(getRandomInt(0,mask.length)); //Pick random char
            outputValue += randomChar;
        }
        outputValue = shuffleString(outputValue); //shuffle output

        if (passwordChecker(outputValue, minFieldNum)) {
            return outputValue + passwordChecker(outputValue, minFieldNum);
        }
        else {
            console.log("error password", outputValue);
        }

    }
}

function shuffleString(inputString) {
    var array = inputString.split('');
    for (var i = array.length - 1; i > 0; i--) {
        var j = Math.floor(Math.random() * (i + 1));
        var temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }
    return array.join('');
}

function getRandomInt(min, max) {
    var byteArray = new Uint8Array(1);
    window.crypto.getRandomValues(byteArray);
    var range = (max - min);
    var output =  min  + (byteArray[0] % range);

    return output
}

function passwordChecker(output, minSize){
    var checkChars = '!"$%^&*(){}[];#,./:@~<>?|_+-=';
    if (output.length < minSize){
        console.log("too short")
        return false
    }
    else if((output.toUpperCase() != output) && (output.toLowerCase() != output)) {
        for (var i = 0; i < output.length; i++) {
            if (checkChars.indexOf(output.charAt(i)) != -1) {
                if(output.indexOf(' ') === -1){
                    return true;
                }

            }
        }
    }
    console.log("doesn't meet standards")
    return false;
}

for(j=0; j<10000; j++){
    cryptoPassword()
}
console.log("done")

我在底部添加了一个快速测试。它将生成10,000个密码。如果测试失败,它只会将它们输出到控制台。你可能想要删除它和一些console.log并稍微整理一下。