Генератор паролей Javascript с добавлением пробелов и неудачных тестов

Я пытаюсь создать генератор паролей, который создает пароли, соответствующие:

  1. Не менее 8 символов в длину, не более 40 символов в длину
  2. Должен содержать как минимум 1 заглавную, строчную букву, число и символ

Я избегаю Math.random по своему выбору, я предпочитаю опцию crypto.

Я прошел через множество статей, чтобы попытаться заставить это работать, но у меня есть следующие проблемы:

  1. Случайные пробелы появляются в выходной строке, часто в конце.

  2. Выходные значения иногда не соответствуют правилу min 8 char.

Я понимаю, что, возможно, у меня слишком много дополнительных операторов, если они дважды проверяют вещи, но я изо всех сил пытаюсь понять, в чем дело.

Это относится к другой системе, поэтому я создаю ее как можно более модульной и функциональной. Извинения за большой фрагмент ниже, я не мог заставить его работать в 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 ответ

Таким образом, проблема, похоже, связана с функцией getRandomInt, которая возвращает int между 0 и длиной маски. Поскольку вы имеете дело с массивами, вы действительно хотите, чтобы он был между 0 и длиной массива -1.

Вы возвращали пустые строки из функции charAt, когда просили позицию вне массива.

Я исправил это, а также немного оптимизировал секцию генерации. Он всегда добавляет по одному символу от каждой из масок, а затем выбирает их случайным образом. Затем я тасую строку, перемещая начальные 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")

Я добавил быстрый тест внизу. Он сгенерирует 10000 паролей. Он выведет их на консоль, только если они не пройдут ваш тест. Вы, вероятно, захотите удалить это и некоторые из console.logs и немного привести в порядок.

Другие вопросы по тегам