1

First time posting. Very new to javascript. I have a project where I have to create a random password generator. I have managed to get it working but my problem is the following.

Say for example the user picks a password length of 8 characters long and all 4 confirms for password criteria is true. When the password is generated there is a chance that it will be missing some of the criteria because it is all in one big pool.

Any help would be appreciated. Thanks.

// Assignment Code.
var generateBtn = document.querySelector("#generate");

// Created a function named passwordValidation to check if the parameter userInput after the prompt is true. If not it returns false and the user will have to try again.
// The return true value is outside of the if else statements because if the user input is true it does not need to go inside the if else statements. 
var passwordValidation = (userInput) => {
  if (userInput === null) {
    alert('You pressed cancel. Please try again')
    return false;
  } else if (userInput < 8 || userInput > 128) {
    alert('Please try again. Your password must be between 8 and 128 numerical characters long')
    return false;
  } else if (isNaN(userInput)) {
    alert('Please enter a valid number input')
    return false;
  }
  return true;
};


// Variables section that contain arrays with all the characters needed.
let lowCase = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"];
let upCase = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"];
let numCase = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9,];
let specCase = ["!", "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/", ":", ";", "<", "=", ">", "?", "@", "[", "]", "^", "_", "`", "{", "|", "}", "~"];

// Created a function named userConfirmationInput that passes passwordLength as a parameter.
var userConfirmationInput = (passwordLength) => {

  // Initialized an empty array to store the password, passwordArray.push located under the for loop stores the password here.
  // Check scope, passwordArray is in a function, but not inside for loops or if statements so that it can be accessed anywhere inside of the function. 
  let passwordArray = [];

  // These below check for if the input is true or not, when the user selects yes or no from the confirms.
  let isLow = confirm("Would you like to include lower case letters?");
  let isUp = confirm('Would you like to include upper case letters?');
  let isNum = confirm('Would you like to include numbers?');
  let isSpec = confirm('Would you like to include special characters?');

  // Initialzed another empty array like we're doing with password. Reason why is if the array is inside of the if statement, it cannot be accessed due to scope.
  let randomSelectionArray = []

  // If no option is selected
  if (!isLow && !isUp && !isNum && !isSpec) {
    alert('You must select at least one option')
    return false;

    // The purpose of an empty array is for the storage of letters, numbers or special characters. 
    // The lines below will do a check for what options have been selected.
  } else if (isLow && isUp && isNum && isSpec) {
    // This line below will add the array of lowCase, upCase, numCase and specCase to the randomSelectionArray. 
    // Concat will join and add the users selected arrays to the randomSelectionArray.
    randomSelectionArray = randomSelectionArray.concat(lowCase, upCase, numCase, specCase)
    console.log(randomSelectionArray);

    //Three options true.
  } else if (isLow && isUp && isNum) {
    randomSelectionArray = randomSelectionArray.concat(lowCase, upCase, numCase);
  } else if (isLow && isUp && isSpec) {
    randomSelectionArray = randomSelectionArray.concat(lowCase, upCase, specCase);
  } else if (isLow && isNum && isSpec) {
    randomSelectionArray = randomSelectionArray.concat(lowCase, numCase, specCase);
  } else if (isUp && isNum && isSpec) {
    randomSelectionArray = randomSelectionArray.concat(upCase, numCase, specCase);


    //Two options true.
  } else if (isLow && isUp) {
    randomSelectionArray = randomSelectionArray.concat(lowCase, upCase);
  } else if (isLow && isNum) {
    randomSelectionArray = randomSelectionArray.concat(lowCase, numCase);
  } else if (isLow && isSpec) {
    randomSelectionArray = randomSelectionArray.concat(lowCase, specCase);
  } else if (isUp && isSpec) {
    randomSelectionArray = randomSelectionArray.concat(upCase, specCase);
  } else if (isUp && isSpec) {
    randomSelectionArray = randomSelectionArray.concat(upCase, specCase);
  } else if (isNum && isSpec) {
    randomSelectionArray = randomSelectionArray.concat(numCase, specCase);


    //One option true.
  } else if (isLow) {
    randomSelectionArray = randomSelectionArray.concat(lowCase);
  } else if (isUp) {
    randomSelectionArray = randomSelectionArray.concat(upCase);
  } else if (isNum) {
    randomSelectionArray = randomSelectionArray.concat(numCase);
  } else if (isSpec) {
    randomSelectionArray = randomSelectionArray.concat(specCase);
  }

  // For loop below will be based on the length that the user wants the password to be. 
  for (var i = 0; i < passwordLength; i++) {
    // RandomCharacter is the variavle that stores the output of the functions below.
    let randomCharacter = Math.floor(Math.random() * randomSelectionArray.length);
    // This will randomly select X amount of times (what password Length is) the position of the randomCharacter in the randomSelectionArray.
    // passwordArray.push will add the position of randomCharacter in the randomSelectionArray to the passwordArray.
    passwordArray.push(randomSelectionArray[randomCharacter])
  }
  // Code below remove commas and quotation marks.
  return passwordArray.join("");
}


var generatePassword = () => {
  var passwordLength = prompt('Please enter a numerical password length that is between 8 and 128 characters long')
  // PasswordValidation returns true or false, so if it is true, it will return the values of userConfirmationInput. which is the password.
  if (passwordValidation(passwordLength)) {
    return (userConfirmationInput(passwordLength))
  } else {
    console.log('no')
  }

}
// Write password to the #password input
const writePassword = () => {

  // The function userConfirmationInput returns passwordArray.join(" ") which is just our string. passwordArray.join removes the quotes and the commas.
  // Then in the generatePassword function, we are returning the value of the function userConfirmationInput. 
  // Variable password will assign the value of generatePassword to password, which is being assigned to the component passwordText.
  var password = generatePassword();
  var passwordText = document.querySelector("#password");

  passwordText.value = password;

}

// Add event listener to generate button
generateBtn.addEventListener("click", writePassword);
LDN
  • 11
  • 2

1 Answers1

1

Your prompt to the user is confusing: 'Please choose a password between 8 and 128 characters'

That should probably read 'Please choose a password length between 8 and 128 characters' - right?

That gets the focus where it belongs.

Rather than concatenating the arrays of possible characters, you might consider placing each array into an array of arrays:

const chars = [];
chars.push(["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]);
chars.push([["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]);
chars.push([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ]);
chars.push(["!", "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/", ":", ";", "<", "=", ">", "?", "@", "[", "]", "^", "_", "`", "{", "|", "}", "~"]);

Then use two random numbers:

  1. First between 1 & chars.length to randomize the source
  2. Second between 1 & source.length to randomize the pick of char

const passwordLength = 8;
const chars = [];
chars.push(["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]);
chars.push(["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]);
chars.push([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ]);
chars.push(["!", "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/", ":", ";", "<", "=", ">", "?", "@", "[", "]", "^", "_", "`", "{", "|", "}", "~"]);


let password = '';
for (let i = 0; i < passwordLength; i++) {
  let randomSource = Math.floor(Math.random() * chars.length);
  let randomCharacter = Math.floor(Math.random() * chars[randomSource].length);
  password += chars[randomSource][randomCharacter];
}

console.log(password);
Randy Casburn
  • 11,404
  • 1
  • 12
  • 26
  • The tests do not fail. The problem is if a user picks a password with a length of 8 characters and selects yes to confirm lower case letters, upper case letters, numbers, and special characters there is a chance that the password generated could miss one of the four selected criteria because the arrays have been joined and randomized. – LDN Oct 18 '20 at 21:55
  • I am very confused. When I run it in a browser everything seems to be working fine. I am just having the problem I mentioned about getting the 4 options selected to always be present in the generated password... – LDN Oct 18 '20 at 22:46
  • please see the edit - the user prompt made it appear you wanted a password in the prompt rather than a password length. In sync with you now. – Randy Casburn Oct 18 '20 at 23:42
  • Yes, you are correct, my prompt() text should have been more clear. My apologies. – LDN Oct 18 '20 at 23:55