Password characters checker in JavaScript - javascript

I'm trying to build something that checks the password that I enter in a prompt has a upper case letter , one lower case , one special symbol and a length...but sometimes when I am entering just upper case cand lower case letters I get no alert ( you will see it in the code )..
Also I have the following error in the console : Cannot read property 'length' of null at hasUpperCase"
I will post the code here:
var parola = prompt('Introdu parola:');
function hasUpperCase(parola){
for(i = 0; i < parola.length; i++){
if(parola[i] === parola[i].toUpperCase()){
return true;
}
}
}
function hasLowerCase(parola){
for(i = 0; i < parola.length; i++){
if(parola[i] === parola[i].toLowerCase()){
return true;
}
}
}
var minLength = 8;
function isLongEnough(parola){
if(parola.length >= minLength){
return true;
}
}
function hasSpecialCharacter(parola){
var specialCharacters = "£$%^&*#~";
for(i = 0; i < parola.length; i++){
for(j = 0; j < specialCharacters.length; j++){
if(parola[i] === specialCharacters[j]){
return true;
}
}
}
}
function isPasswordValid(parola){
if(!hasUpperCase(parola)){
alert('The password requires a capital letter!');
var parola = prompt('Introdu parola:');
}
if(!hasLowerCase(parola)){
alert('The password requires a lower case letter!');
var parola = prompt('Introdu parola:');
}
if(!isLongEnough(parola)){
alert('The password is not long enough!');
var parola = prompt('Introdu parola:');
}
if(!hasSpecialCharacter(parola)){
alert('The password requires a special character');
var parola = prompt('Introdu parola:');
}
if((hasSpecialCharacter(parola) && hasLowerCase(parola) && hasUpperCase(parola) && isLongEnough(parola)){
}
}
isPasswordValid(parola);

Aside from implementation concerns, first fix the error by checking for null or undefined first thing in your isPasswordValid function. Also, as wisely suggested by Patrick, use regex for these checks. I'd also recommend always returning a bool in your check functions by returning false after each for loop.

You could use the the regex
/^(?=.{1,}[a-z])(?=.{1,}[A-Z])(?=.{1,}([£$%^&*#~])).{8,20}$/
to match all of those examples.
Here's a brief explanation:
^ // the start of the string
(?=.{1,}[a-z]) // use positive look ahead to see if at least one lower case letter exists
(?=.{1,}[A-Z]) // use positive look ahead to see if at least one upper case letter exists
(?=.{1,}[£$%^&*#~]) // use positive look ahead to see if at least one underscore or special character exists
.{8,20} // gobble up the entire string and match between 8 and 20
$ // the end of the string
You would use it like this:
function isPasswordValid(parola)
{
if(!parola)
return false;
var reg = /^(?=.{1,}[a-z])(?=.{1,}[A-Z])(?=.{1,}([£$%^&*#~])).{8,20}$/g;
if(parola && reg.test(parola)){
//do stuff here
}
}
if you don't want to do all of that, for your code its a very simple fix!
remove the extra ( and add this to your test:
function isPasswordValid(parola){
if(!parola)
return false;
.
.
.
.
.
.
if(parola && (hasSpecialCharacter(parola) && hasLowerCase(parola) && hasUpperCase(parola) && isLongEnough(parola))){
// do stuff here
}
checking just the varriable will evaluate as false if it is:
null
undefined
NaN
empty string ("")
0
false
and as true otherwise.
This should fix all of your issues.
UPDATE
Thank you Patrick Roberts for pointing out the error in the regex. below is a working example.
const regex = /^(?=.{1,}[a-z])(?=.{1,}[A-Z])(?=.{1,}([£$%^&*#~])).{8,20}$/g;
const str = 'aA$';
let m;
if ((m = regex.exec(str)) !== null) {
// The result can be accessed through the `m`-variable.
m.forEach((match, groupIndex) => {
console.log(`Found match, group ${groupIndex}: ${match}`);
});
}
else{
console.log('no match found')
}

To address the error you mentioned, namely
Cannot read property 'length' of null at hasUpperCase
You must check that the value returned from prompt() is not null as a result of the input being cancelled by the user.
Otherwise, you can read the string from an <input> to ensure that the value is always a string.
Some other issues are that you don't take advantage of the simplicity of regular expressions to enforce some of the constraints you implement with for loops, which would make your code a lot more readable, maintainable, and easier to digest.
Also as I suggested in the comments, it's better practice to allow isLongEnough() to accept a parameter, a local variable, or even the minlength attribute on the password to indicate the minimum length, rather than a scoped variable as is currently being used.
Finally, it would help to take advantage of the pattern attribute of the <input> element to automate some of the requirements that can be expressed in a regular expression. Note, I tried to include this in the solution below, but the look-aheads in pattern="(?=[a-z])(?=[A-Z])(?=[£$%^&*#~])" seemed to behave kind of buggy, so I've omitted this particular suggestion.
Working these suggestions into a solution might look something like this:
function hasUpperCase(parola) {
return /[A-Z]/.test(parola);
}
function hasLowerCase(parola) {
return /[a-z]/.test(parola);
}
function isLongEnough(parola, minLength) {
return parola.length >= minLength;
}
function hasSpecialCharacter(parola) {
return /[£$%^&*#~]/.test(parola);
}
function checkPasswordValidity() {
var parola = this.value;
var minLength = Number(this.getAttribute('minlength'));
var errors = [];
if (!isLongEnough(parola, minLength)) {
errors.push('a minimum length of ' + minLength + ' characters');
}
if (!hasUpperCase(parola)) {
errors.push('a capital letter');
}
if (!hasLowerCase(parola)) {
errors.push('a lower case letter');
}
if (!hasSpecialCharacter(parola)) {
errors.push('a special character');
}
if (errors.length > 0) {
this.setCustomValidity('The password requires ' + errors.join(', '));
} else {
this.setCustomValidity('');
}
}
document.querySelector('[name="password"]').addEventListener('input', checkPasswordValidity);
<form>
<input name="password" type="text" placeholder="Introdu parola" minlength="8" required>
<input type="submit" value="Submit">
</form>

That error was cause of the prompt cancellation. So, i think you should be using the value in the text field and validate that
Here is the working way for doing that
$('#form').on('submit', function() {
event.preventDefault();
var parola = $('#txt_name').val();
isPasswordValid(parola);
})
function hasUpperCase(parola){
for(i = 0; i < parola.length; i++){
if(parola[i] === parola[i].toUpperCase()){
return true;
}
}
}
function hasLowerCase(parola){
for(i = 0; i < parola.length; i++){
if(parola[i] === parola[i].toLowerCase()){
return true;
}
}
}
var minLength = 8;
function isLongEnough(parola){
if(parola.length >= minLength){
return true;
}
}
function hasSpecialCharacter(parola){
var specialCharacters = "£$%^&*#~";
for(i = 0; i < parola.length; i++){
for(j = 0; j < specialCharacters.length; j++){
if(parola[i] === specialCharacters[j]){
return true;
}
}
}
}
function isPasswordValid(parola){
if(!hasUpperCase(parola)){
alert('The password requires a capital letter!');
return;
}
if(!hasLowerCase(parola)){
alert('The password requires a lower case letter!');
return;
}
if(!isLongEnough(parola)){
alert('The password is not long enough!');
return;
}
if(!hasSpecialCharacter(parola)){
alert('The password requires a special character');
return;
}
if(hasSpecialCharacter(parola) && hasLowerCase(parola) && hasUpperCase(parola) && isLongEnough(parola)){
alert('yayyy!!');
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form id="form">
<input type="text" name="text" value="" id="txt_name">
<input type="submit" value="Check password">
</form>

isPasswordValid calls your 4 functions in sequence to check their validity, but does not re-check the prompt's value if any of them fail. It just asks you to enter something else and then continues on. You can re-check the prompt's validity by re-calling isPasswordValid at the end of the function. Calling it at the end of the function prevents additional prompts from appearing when you enter invalid inputs and then a valid one.
Note: calling toLowerCase() on a symbol returns that symbol, so ####AAAA would have been valid. To get around this I used regular expressions in your functions.
var parola = prompt('Introdu parola:');
function hasUpperCase(parola) {
return /[A-Z]/.test(parola)
}
function hasLowerCase(parola) {
return /[a-z]/.test(parola);
}
var minLength = 8;
function isLongEnough(parola) {
return parola.length >= minLength;
}
function hasSpecialCharacter(parola) {
return /[£$%^&*#~]/.test(parola);
}
var errorMessage;
function isPasswordValid(parola) {
if (!hasUpperCase(parola)) {
errorMessage = 'The password requires a capital letter!';
}
else if (!hasLowerCase(parola)) {
errorMessage = 'The password requires a lower case letter!';
}
else if (!isLongEnough(parola)) {
errorMessage = 'The password is not long enough!';
}
else if (!hasSpecialCharacter(parola)) {
errorMessage = 'The password requires a special character';
}
else {
alert('Password is valid');
return;
}
parola = prompt(errorMessage);
isPasswordValid(parola);
}
isPasswordValid(parola);

Related

How to give "No more tries left" in a password-guessing loop

I've just started learning JS and I got stuck here.
What I need to do:
If you don't enter the correct password, you get the message "Try again".
If you don't enter the password 3 times, you get the message "No more tries left".
If you enter the correct password, you get the message "You may enter".
Here's my code:
for ( let i = 3; i > 0; i-- ) {
let password = prompt("What is the password?")
if ( password.toUpperCase() !== "BINGO" ) {
alert("Try again")
} else if ( i = 0 ) {
alert("No more tries left")
} else {
alert("You may enter")
}
}
I can't get it work properly as the message "No more tries left" doesn't show up. I know ( i = 0 ) is wrong but I don't know how to make it work.
Firstly, make sure that you're not using an assignment operator when you check if i == 0. You're currently using i = 0, which doesn't check if the two are equal as much as it assigns the left to the right. No bueno.
Secondly, your for loop is off just by a bit. It'll never get to 0 because you've asked it to loop while i > 0, not i >= 0. But wait - if you use i >= 0, it'll loop four times. That's not what you want either. We'll compromise and loop three times, but check if i == 1 instead of 0.
Here's my corrected code that works:
// loop three times
for ( let i = 3; i > 0; i-- ) {
let password = prompt("What is the password?")
// if it's the correct answer then alert and break the loop
if ( password.toUpperCase() == "BINGO" ) {
alert("You may enter")
break
// if it's not, and the tries has elapsed, then alert and break the loop
} else if ( i == 1 ) {
alert("No more tries left")
break
// if it's not but the tries have not elapsed, then loop again
} else {
alert("Try again")
}
}
Try this.
for ( let i = 3; i >= 0; i-- ) {
if (i===0){
alert("No more tries left");
break;
}
let password = prompt("What is the password?")
if ( password.toUpperCase() !== "BINGO" ) {
alert("Try again")
} else {
alert("You may enter")
}
}
Give the user chance to enter the password 3 times but loop 4 times and check if the loop runs for 4th times(i === 0). if prompt No more tries left and break the loop.
You are using an assignment operator instead of a comparison operator.
Change this:
else if ( i = 0 ) {
alert("No more tries left")
}
To this :
else if ( i == 0 ) {
alert("No more tries left")
}
Try this. It will run the loop until they have entered the password correctly or the number of attempts is 3.
After the loop you can then just check if valid is true or false.
let valid = false;
let attempts = 0;
do
{
const password = prompt('What is the password');
valid = password.toUpperCase() === 'BINGO';
if (!valid && attempts < 2)
{
alert('Try again');
}
attempts++;
} while (!valid && attempts < 3)
if (valid)
{
alert('You may enter');
} else
{
alert('No more tries left');
}
You are asking the user to enter the password in each iteration
using a loop. So, showing that "you don't have anymore attempt left"
is useless here. Because if the value is greater than 3, the
instruction inside the loop will not be executed.
Do not use JavaScript for authentication. It is a client side
programming language and any one who knows how things work can
extract the password. Instead use a back-end language for
authentication such as PHP, Node.js
But if you only want to know about it just for the learning purpose
not because you wanna implement it, the below code will help you
for (let i=0; i<3; i++){
let password = prompt("what is the password: ");
if (password.toUpperCase() != "BINGO"){
alert("Try Again!");
}else{
alert("You may enter!");
i=3;
}
}
There are several ways you can do the "No more attempt left" is, one of the simple and basic is:
<input type="button" value="Enter Code" onclick="checkMe()">
<script>
let i=0;
function checkMe(){
if (i<3){
let password = prompt("Enter password!");
if (password.toUpperCase() != "BINGO"){
alert("Try Again! Attempt "+ (++i));
}else{
alert("You may enter!");
i=3;
}
}else alert("No more attempts left");
}
</script>
The above code can be implemented using input field, as i said, there are several ways. Hope it helps!
Your code is fine, what goes wrong is that it does not fall into the if condition (i == 0), because the loop only runs while i > 0,
just need to adjust like this:
for ( let i = 3; i > 0; i-- ) {
let password = prompt("What is the password?")
if (password.toUpperCase() !== "BINGO" && i > 1 ) {
alert("Try again")
} else if (i == 1 && password.toUpperCase() !== "BINGO") {
alert("No more tries left")
} else {
alert("You may enter")
i = 0
}
}

My code should be detecting if a string has currency symbols, but it will not detect £

My code is supposed to detect currency symbols, and execute code based on the result, but the code will not detect the '£' under any circumstances. Here is the relevant code:
let requirements = [ "£", "$" ];
let mcontent = "$£50";
let y = 0;
for (let p = 0; p < requirements.length; ++p) {
if (mcontent.includes(requirements[p])) {
++y;
}
}
if (y == 1) {
//this is considered success, only ONE currency symbol was detected. If mcontent = '$50' or '£50', we should be here.
} else {
//this is considered failure, TWO or ZERO currency symbols were detected. In this scenario, I want the code to fail.
}
I'm aware this may not be the best way to code a function to accomplish what I'm trying to accomplish, so I'm open for better ideas/fixes for what I already have.
The most concise way to do this is to check with RegExp like this:
if (mcontent.match(/£|\$/g)?.length == 1) { // the question mark is so we don't encounter an error if no matches were found
// success
} else {
// failure
}
Here's a live example:
const mcontent1 = '$£50';
const mcontent2 = '£50';
const mcontent3 = '$50';
const regex = /£|\$/g; // slash to escape $ because it has special meaning in regex
console.log(mcontent1.match(regex).length == 1); // false
console.log(mcontent2.match(regex).length == 1); // true
console.log(mcontent3.match(regex).length == 1); // true
If you don't want to use regex, just check if the string includes a symbol, increment a counter, and return whether or not there was exactly 1 match:
let testA = "$£50",
testB = "£50",
testC = "$50";
function checkString(str) {
const symbols = ["£", "$"];
let matches = 0;
for (const symbol of symbols)
if (str.includes(symbol)) matches++;
return matches == 1;
}
console.log(
checkString(testA),
checkString(testB),
checkString(testC)
);
Use RegExp it will return true or flase based on value entred
this example will give you an idea of how to use it
const elementTwo = document.getElementById('elementTwo');
elementTwo.addEventListener("input", function(event) {
pattern = /^[£|$]{1}(\d+)/
if (pattern.test(this.value)) {
console.log("found")
} else console.log("not found")
});
<p>Enter value</p>
<input id="elementTwo" type="text" />

Required only one dot at the end of nameserver

The regex below works nice except I need only one dot (.) at the end for nameserver. For example if user submit ns1.hello.com there will be error. Accepted format is with dot at the end like this ns1.hello.com. Help me please. Thank you.
<script type="text/javascript">
function validSubdomain() {
var re = /^[a-zA-Z0-9][a-zA-Z0-9.-]+\.$/;
var val = document.getElementById("nameserver").value;
var val2 = document.getElementById("nameserver2").value;
if(val == '' && val2 == ''){
alert("Please fill in the name server");
document.forms['namaform'].elements['nameserver'].focus();
return false;
}
if(val == ''){
alert("Please fill in the name server 1");
document.forms['namaform'].elements['nameserver'].focus();
return false;
}
if(val2 == ''){
alert("Please fill in the name server 2");
document.forms['namaform'].elements['nameserver2'].focus();
return false;
}
var parts = val.split('.');
var parts2 = val2.split('.');
if (parts.length < 3)
{ alert('invalid nameserver format')
document.forms['namaform'].elements['nameserver'].focus();
return false;
}
else if (parts2.length < 3)
{ alert('invalid nameserver 2 format')
document.forms['namaform'].elements['nameserver2'].focus();
return false;
}
if( !re.test(val)) {
alert("invalid nameserver 1 format");
return false;
}
else if( !re.test(val2)) {
alert("invalid nameserver 2 format");
}
else{namaform.submit();}
}
</script>
Two things wrong with:
if(re.test(val && val2)) {
alert("valid format");
}
if(!re.test(val && val2)) {
alert("invalid format");
}
First of all, have you never heard of else? It's there specifically so you don't have to repeat a test in the negative.
Second, you are trying to && together the two string and then passing the resulting boolean to re.test(). Since a boolean converts to the string "true" or "false" it will never ever match.
Change to:
if( re.test(val) && re.test(val2)) {
alert("valid format");
}
else {
alert("invalid format");
}
Also note that your regex is wrong. It would accept a..b as input, which is clearly not valid. Try this instead:
var re = /^([a-z0-9-]+\.)+[a-z]{2,3}\.$/i;
This will broadly match most domains with unlimited number of subdomain levels, provided there's a . at the end.
EDIT to disallow - at the front of a section:
var re = /^([a-z0-9][a-z0-9-]*\.)+[a-z]{2,3}\.$/i;
It sounds like you're just saying that this:
var re = /^[a-zA-Z0-9][a-zA-Z0-9.-]+[a-zA-Z0-9]$/;
needs to be this:
var re = /^[a-zA-Z0-9][a-zA-Z0-9.-]+\.$/;
?
If you want to match a special character in a regex (also referred to as 'metacharacters') you need to escape it with a backslash. So, just before the $ in your regex, include
\.
to match the dot at the end of the string.

Check field with at least one or more digits and including characters

I'm making a contact form which will be submitted with jQuery and I'm stuck on one simple validation.
I need to validate a field, which has to have at least x integers.
How can I do this?
p.s: please don't suggest validation plugin.
Thanks,
edit: This is what I've tried, but it's wrong I guess.
var numbercheck = /^(\w\d{7,14})?$/;
this is jsdiffle:
http://jsfiddle.net/4WqY9/
Use regex providing the range of numbers you can afford in your field
like \d{5,10} // Here 5 -10 is the range of numbers
function testContact(contact){
contact = contact.replace(/[a-z]*/g,"");
return (contact == contact.match(/\d{5,10}/))?true:false;
}
To match a number of integers using a regex you'd need something like:
^((\d*)\s*)*$
I'd write a small function that will do the job. Note that this function will return false if you have any non-int elements in the inputText :-
function HasRequiredIntegers(inputText, requiredIntegers) {
var elems = inputText.split(/\s+/);
var intCount = 0;
var nonIntCount = 0;
for (i = 0; i < elems.length; i++) {
if (((parseFloat(elems[i]) == parseInt(elems[i])) && !isNaN(elems[i]))) {
intCount++;
}
else {
nonIntCount++;
}
}
return (intCount >= requiredIntegers && nonIntCount == 0);
}
Try this
function hasUpTo5(strin){
if( string.replace(/[^0-9]/g, '').length <= 5){
return true
}else{
return false;
}
}
alert( hasUpTo5("fhsfbgurb3utn55nun44") );

javascript validation to check # at start of user input: not email validation

I have to check whether a form field contains '#' at start of user input & is it contains it at all. It works fine for checking if its at start of the string. But when I add checking whether input contains '#' at all or not. It fails. Here is my code
function email_valid(field)
{
var apos=field.update.value;
apos=apos.indexOf('#');
if (apos>0 ||((apos.contains('#')== 'FALSE')))
{ alert('plz enter valid input');
return false;
}
else
{ return true; }
}
EDIT
This function in this form is checking both if # is at 1st place & 2ndly is it in the input at all or not.
function #_valid(field)
{
var ref=field.update.value;// I needed ref 4 other things
var apos=ref.indexOf('#');
if (apos>=0 )
{
if (apos==0)
{
return true;
}
else { field.t_update3.value="";
alert('plz enter a valid refernce');
return false;
}
}
else { field.t_update3.value="";
alert('plz enter a valid refernce');
return false;
} }
Consider:
var apos = value.indexOf('#');
if (apos >= 0) {
// was found in string, somewhere
if (apos == 0) {
// was at start
} else {
// was elsewhere
}
} else {
// not in string
}
and
var apos = value.indexOf('#');
if (apos == 0) {
// was at start
} else if (apos > 0) {
// was elsewhere
} else {
// not in string
}
Why not just
if (apos !== 0) { /* error; */ }
The "apos" value will be the numeric value zero when your input is (as I understand it) valid, and either -1 or greater than 0 when invalid.
This seems like a strange thing to make a user of your site do, but whatever. (If it's not there at all, and it must be there to be valid, why can't you just add the "#" for the user?)
You can just check to make sure that apos is greater than -1. Javascript's indexOf() will return the current index of the character you're looking for and -1 if it's not in the string.
edit Misread a bit. Also make sure that it's not equal to 0, so that it's not at the beginning of the string.
function email_valid(field)
{
var fieldValue =field.update.value;
var apos = apos.indexOf('#');
if (apos > 0 || apos < 0)//could also use apos !== 0
{ alert('plz enter valid input');
return false;
}
else
{ return true; }
}
apos is the value returned by indexOf, it will be -1 if there is no # in the user input. It will be 0 if it is the first character. It will be greater than 0 if the user input contains an # . JavaScript has no contains method on a String.
Try:
function email_valid(field) {
//var apos=field.update.value;
var apos = field;
//apos=apos.indexOf('#');
apos = apos.indexOf('#');
if( (apos < 0) ) {
//alert('plz enter valid input');
alert('false');
} else {
alert('true');
}
}
email_valid('blah');
Checks for # anywhere. Or, if you want to check for # just at the beginning, change if( (apos < 0) ) { to if( (apos == 0) ) {. Or, if you want to make sure it's not at the beginning, then if( (apos > 0) ) {.
apos will be -1 if the string was not found. So your code should be as follows:
function email_valid(field)
{
var apos=field.value;
apos=apos.indexOf('#');
if (apos<=0) // handles '#' at the beginning and not in string at all.
{
alert('plz enter valid input');
return false;
}
else
{ return true; }
}
I also changed your initial assignment to remove the .update portion as that would cause it to fail when field is a reference to an input.
In the second if condition, apos is a number, not a string.
You're trying to write
if (field.update.value.charAt(0) == '#' && field.update.value.indexOf('#', 1) < 0)
Learn about Regular expressions if you haven't already. Then lookup Javascript's String#match. There is no need to find wether the input starts with an "#" as if it contains an "#" that will also return true if the "#" is at the start of the string.
Also, for free, return true and return false are generally bad style. Just return the thing you passed to if (that evaluates to a boolean).
All in all:
function validate_input(str) {
return str.match(/#/);
}
I reccomend passing the function a string (field.value or some-such) rather than the field itself as it makes it more generic.
Update: revised answer based on comments. code below will only return true if the value contains an "#" symbol at the first character.
If this is a JavaScript question, then this should be fine.
function email_valid(field){
var apos=field.update.value;
if(apos.indexOf('#') != 0){
alert('plz enter valid input');
return false;
} else {
//field contains an '#' at the first position (index zero)
return true;
}
}
That said, your parameter "field" if it actually refers to an input field element, should only require this code to get the value (e.g. I'm not sure where the ".update" bit comes into play)
var apos = field.value;
I would also rename this function if it isn't doing "email validation" to something a little more appropriately named.

Categories