Alert function in Node.js not working in some cases - javascript

I'm a newbie at node.js, and trying to make a login page.
When I'm trying to login with the right credentials the page works as intended. Also worth noting is that when I try to login with no credentials the alert window pops up. But when I try to login with the wrong credentials, it just won't work. I've tracked the error back to "alert" function, but I cannot understand why in the world the alert function works when calling it to display the alert that no username nor password was inserted, but will crash when I'm trying to display that the username and password are wrong. I'm pretty certain that the error comes from the alert function.
The code is below.
Thanks alot!
app.post('/auth', function(request, response) {
var username = request.body.username;
var password = request.body.password;
if (username && password) {
connection.query('SELECT * FROM accounts WHERE username = ? AND password = ?', [username, password], function(error, results, fields) {
if (results.length > 0) {
request.session.loggedin = true;
request.session.username = username;
response.redirect('/home');
response.end();
} else {
alert('Incorrect Username and/or Password!');
}
});
} else {
alert('Please enter Username and Password!');
}
});

but I cannot understand why in the world the alert function works when calling it to display the alert that no username nor password was inserted
It shouldn't do.
alert isn't a function provided by Node.js. It belongs to browsers so it can show something in the browser UI.
To send something from a server built on Node.js back to the browser then:
The something needs to be data
You need to send it by calling a method (like render, json or send) on the response object.

Related

Firebase: Email verification link always expired even though verification works

I'm trying to set up an email verification flow in my project, but I can't seem to get it right.
How my flow works now is the user enters their credentials (email and password), which are used to create a new firebase user. Then, once that promise is resolved, it sends an email verification link to the new user that was created. The code looks like this:
async createUser(email: string, password: string) {
try {
console.log("Creating user...");
const userCredentials = await createUserWithEmailAndPassword(
auth,
email,
password
);
console.log("Successfully created user");
const { user } = userCredentials;
console.log("Sending email verification link...");
await this.verifyEmail(user);
console.log("EMAIL VERIFICATION LINK SUCCESSFULLY SENT");
return user;
} catch (err) {
throw err;
}
}
async verifyEmail(user: User) {
try {
sendEmailVerification(user);
} catch (err) {
throw err;
}
}
The link is sent through fine, but once I press on it, I'm redirected to a page that says this:
Strangely, the user's email is verified after this, in spite of the error message displayed. Any idea why this is happening?
Update:
I managed to figure it out. The email provider I'm using is my university's, and it seems to be preventing the verification link from working properly. I did try with my personal email to see if that was the case, but I wasn't seeing the verification link appearing there. I eventually realized that it was because it was being stored in the spam folder. It's working on other email providers, though, ideally, I'd want it to work on my university's email provider (the emails that users sign up with are supposed to be exclusively student emails). Any ideas how I could resolve this?
I eventually figured out that the issue was with my email provider. I was using my student email, which the university provides, and I imagine they've placed rigorous measures in place to secure them as much as possible. I have no idea what was preventing it from working, but I managed to figure out a workaround.
In brief, I changed the action URL in the template (which can be found in the console for your Firebase project in the Authentication section, under the Templates tab) to a route on my website titled /authenticate. I created a module to handle email verification. Included in it is a function that parses the URL, extracting the mode (email verification, password reset, etc.), actionCode (this is the important one. It stores the id that Firebase decodes to determine if it's valid), continueURL (optional), and lang (optional).
export const parseUrl = (queryString: string) => {
const urlParams = new URLSearchParams(window.location.search);
const mode = urlParams.get("mode");
const actionCode = urlParams.get("oobCode");
const continueUrl = urlParams.get("continueUrl");
const lang = urlParams.get("lang") ?? "en";
return { mode, actionCode, continueUrl, lang };
};
I created another method that handles the email verification by applying the actionCode from the URL using Firebase's applyActionCode.
export const handleVerifyEmail = async (
actionCode: string,
continueUrl?: string,
lang?: string
) => {
try {
await applyActionCode(auth, actionCode);
return { alreadyVerified: false };
} catch (err) {
if (err instanceof FirebaseError) {
switch (err.code) {
case "auth/invalid-action-code": {
return { alreadyVerified: true };
}
}
}
throw err;
}
};
The auth/invalid-action-code error seems to be thrown when the user is already verified. I don't throw an error for it, because I handle this differently to other errors.
Once the user presses the verification link, they're redirected to the /authenticate page on my website. This page then handles the email verification by parsing the query appended to the route. The URL looks something like this http://localhost:3000/authenticate?mode=verifyEmail&oobCode=FLVl85S-ZI13_am0uwWeb4Jy8DUWC3E6kIiwN2LLFpUAAAGDUJHSwA&apiKey=AIzaSyA_V9nKEZeoTOECWaD7UXuzqCzcptmmHQI&lang=en
Of course, in production, the root path would be the name of the website instead of localhost. I have my development environment running on port 3000.
Once the user lands on the authentication page, I handle the email verification in a useEffect() hook (Note: I'm using Next.js, so if you're using a different framework you might have to handle changing the URL differently):
useEffect(() => {
verifyEmail();
async function verifyEmail() {
const { actionCode } = parseUrl(window.location.search);
if (!actionCode) return;
router.replace("/authenticate", undefined, { shallow: true });
setLoadingState(LoadingState.LOADING);
try {
const response = await handleVerifyEmail(actionCode!);
if (response.alreadyVerified) {
setEmailAlreadyVerified(true);
onEmailAlreadyVerified();
return;
}
setLoadingState(LoadingState.SUCCESS);
onSuccess();
} catch (err) {
console.error(err);
onFailure();
setLoadingState(LoadingState.ERROR);
}
}
}, []);
It first checks if there is an action code in the URL, in case a user tries to access the page manually.
The onSuccess, onFailure, and onEmailAlreadyVerified callbacks just display toasts. loadingState and emailAlreadyVerified are used to conditionally render different responses to the user.

How to get resault from function as a response

This is my node.js code. There are two inputs on site, one for username and one for the password. When users enter them, function client.logOn gets them. But there is a third step. The user need to enter the code which he gets on his phone. So, when the user enter the username and password, the script will check if they are good, and if they are, the script will ask me for "twoFactorCode" in cmd, and when I enter it there, everything works. But I want users to enter that code on the page. So how can I do it? In cmd, I only need to enter that 5 character code.
app.post('/api', (request, response) => {
console.log('i got request');
client.logOn({
accountName: request.body.uName,
password: request.body.uPassword,
});});
client.on('loggedOn', () => {
console.log("Logged in");
});

MySql, NodeJS, ExpressJS and bcrypt: what is the best way to handle users' login?

My solution works, but I'm not sure this is safe and appropriate. On the front end I have a ReactJS app that send with axios a request with the login and password. On the back end I have NodeJS + ExpressJS handling the request as follows:
router.post('/', function(req, res, next) {
// get the records that match the login provided
const sql = "SELECT name, surname, login, password, blocked FROM users WHERE login=?";
query(sql, [req.body.login])
.then((result)=> {
// if there are 1 or more results, compare the passwords with bcrypt
if (result.length > 0) {
bcrypt.compare(req.body.password, result[0].password, function(err, success) {
if (success) {
// if the user is not blocked, send the status 200 with user's data
result[0].blocked ?
res.status(401).json({type: 'Warning', message: 'Your account has been blocked. Plase contact the admins.'})
:
res.status(200).json({name: result[0].name, surname: result[0].surname, email: result[0].email});
} else {
// send an error if the password is wrong
res.status(401).json({type: 'Error', message: 'Please check that your login and password are correct.'});
}
});
} else {
// send an error if the login was not found
res.status(401).json({type: 'Error', message: 'Please check that your login and password are correct.'});
}
});
});
Is it enough/safe to query the db for the provided login (it's unique) with if (result.length > 0)?
Is it ok to have the error message contained in the server response like this?
res.status(401).json({type: 'Warning', message: 'Your account has been blocked. Plase contact the admins.'})
I have the chance to let the user know if he typed the correct login but the wrong password; should I let him know that? I think it would give to malicious users the knowledge that the login actually exists, so for now I just send a generic login/pwd error. Is this ok?
Is ok to send the user's data from the server to the client if the login was successful?
Is it ok to have the error message contained in the server response like this?
I have the chance to let the user know if he typed the correct login but the wrong password; should I let him know that? I think it would give to malicious users the knowledge that the login actually exists, so for now I just send a generic login/pwd error. Is this ok?
Your implementation is good enough. It's also a good practice letting users know why they are unable to login without giving out too much information EVEN when it's a problem with their supplied credentials (something you are doing already).
Is it enough/safe to query the db for the provided login (it's unique) with if (result.length > 0)?
Yes, this is fine too. You may also want to add a LIMIT 1 to your query to give you a little performance boost since there is no point having your DB scan through all the records when you expect only one result.
It is also a good practice to only send the minimum amount of information and request for more on demand.
As a general observation of your code, you would benefit from the following:
Doing some error checking on your request object before querying the database at all (good practice too) as there is no guarantee that a valid or well formatted username/password would be sent with the request.
Moving the responses into another file to make your code cleaner and maintainable.

How to query postgres database for existing email

I am trying to create a very simple registration method on my project but I am having trouble figuring out how to stop postgres from adding in people with the same email. I am using postgres and Node.js.
I have an add function that I want to return false my postgres table already has a user with the email he/she tried using. I do the following:
function checkExistingEmail(email, cb){
pg.connect(cstr, function(err, client, done){
if(err){
cb(err);
}
else{
var str = 'SELECT email from Swappers where email=$3';
client.query(str, function(err, result){
if(err){
cb(err);
}
else{
console.log(result.row.email);
if(result.row.email === undefined){
cb(false);
}
else{
cb(true);
}
}
});
}
});
}
Now when I display result.row.email to the console I get that it is undefined. Which is what I want for the first time user, so it should return true, and I should be able to add the user to the database and move on. But that is not the case.
In a file I have called users.js I have the following route handler:
router.post('/authnewuser', function(req,res){
// Grab any messages being sent to use from redirect.
var authmessage = req.flash('auth') || '';
var name = req.body.username;
var password = req.body.password;
var email = req.body.email;
db.checkExistingEmail(email, function(data){
if(data === true)
console.log('success');
else
console.log('fail');
});
});
Now When I run this and try registering the functionality I want is not working. I was wondering if is has to go with my checkExistingEmail function and if I am using results.row.email correctly. Right now When I run this code I just keep getting that it has failed. Which is not what I want. it should be returning true for a new user with an email that has never been saved into the db before.
This is usually not the way to go with a database. Checking first always requires two round-trips to the database. Instead,
put a unique constraint on the "email" column,
just insert the data, and
handle the error you'll get with a duplicate email.
Most inserts will just succeed--one round-trip to the database. And you have to handle errors anyway--there's a lot of reasons an INSERT can fail. So there's not a lot of additional code to write for this specific error.

How to validate user creation on the server in Meteor

What is the best approach to validate user creation on the client and server?
I've tried to validate user creation both server and client side. First I've used methods and Accounts.createUser function but it didn't work even that the documentation says it should.
I've tried different approach. I used Accounts.createUser to validate it on the client and Account.onCreateUser on the server. The problem is that I can't validate password because it's encrypted.
So what is the best way to do it?
For validation of new users, see here
Example from the docs:
// Validate username, sending a specific error message on failure.
Accounts.validateNewUser(function (user) {
if (user.username && user.username.length >= 3)
return true;
throw new Meteor.Error(403, "Username must have at least 3 characters");
});
// Validate username, without a specific error message.
Accounts.validateNewUser(function (user) {
return user.username !== "root";
});

Categories

Resources