I need to authenticate a user, so I call this function:
db.authenticate = function(username,password)
{
var query = this.query("SELECT * FROM users WHERE username = '"+username.toLowerCase()+"' AND password = crypt('"+password+"',password);");
var found = false;
query.on('row', function(row) {
found = true;
console.log("Found:",row.username);
});
if(found){return true;}else{return false;}
}
The problem is, that the function doesn't wait for query.on('row') to finish and just return false..
Any ideas how to solve this?
Since it's an asynchronous function, you need to get your results from a callback.
db.authenticate = function(username, password, callback) {
var query = this.query("SELECT * FROM users WHERE username = '" + username.toLowerCase() + "' AND password = crypt('" + password + "',password);");
query.on('row', function(row) {
console.log("Found:", row.username);
return callback(true);
});
callback(false);
}
Then you'd call it like so:
db.authenticate(username, password, function (isAuthenticated) {
console.log(isAuthenticated); //Will be either true or false.
}
Related
I am new to node.js and I try to render different pages based on some conditions, however, I sometimes meet the problem "Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client", I think this is because of the asynchronous behavior of node.js. How can I fix this problem?
I tried setTimeout but I think that's not the right way to do that.
The following part is the section where I met this issue:
/*
signup err code:
0 stand for no errors,
1 stand for confirmPassword and password not match
2 stand for user already exist
*/
app.post('/signup',(req, res) => {
//initialize the signupErr to be 0
signupErr = 0;
//get the data from the post request
let username = req.body.username;
let email = req.body.email;
let password = req.body.password;
let confirmPassword = req.body.confirmPassword;
let organization = req.body.organization;
/*first check the twice entered password, if not match set error number to 1 for the server to render the corresponding error message*/
if (password!=confirmPassword){
signupErr = 1;
res.redirect('/signup');
}
//form the query to consult the database to check if user exists
let queryUsername = "SELECT password FROM User WHERE Username = " + "'" + username + "'";
let queryEmail = "SELECT email FROM User WHERE Email = " + "'" + email + "'";
// check if username exists
connection.query(queryEmail,(err,results) => {
if(err){
console.log("Errore login: " + err);
} else if(results.length!=0) {
signupErr = 2;
res.redirect('/signup');
}
});
//check if email exists
connection.query(queryUsername,(err,results) => {
if(err){
console.log("Errore login: " + err);
} else if(results.length!=0) {
signupErr = 2;
res.redirect('/signup');
}
});
// form the insertion query if no err found
let queryInsert = "INSERT INTO `PIA`.`User` (`Username`, `Email`, `Password`,`Organization`) VALUES ('"+username +"', '"+ email +"', '"+password +"', '"+organization + "')";
// insert the data into the database
connection.query(queryInsert,(err,results) => {
if(err){
console.log("Errore login: " + err);
} else{
console.log("Inserted");
res.render('main');
}
});
});
The insertion part will still run sometime after the redirect.
I'll be really grateful if you can give me any ideas on how to solve that.
I dont know what to say, i think code says everything. i just want to render something and this error appears, but i dont know why. I tried so many solutions from stackoverflow, and others that i couldn't count them all. Im using mysql2 lib. Please help.
router.get("/:link", function(req, res){
connection.query(
"SELECT * FROM yourshort WHERE link = '" + req.params.link + "'",
function (err, result, rows, fields){
Object.keys(result).forEach(function(key) {
var row = result[key];
console.log(row.link)
if(row.link = req.params.link) {
res.send(row.link + row.views + rows.created)
return;
} else {
res.send("URL does not exist")
return;
}
});
});
});
just because you send it in foreach you get that error .
do you want to send it just one time and first item of db ? if yes use this :
router.get("/:link", function (req, res) {
var i = 0;
connection.query(
"SELECT * FROM yourshort WHERE link = '" + req.params.link + "'",
function (err, result, rows, fields) {
Object.keys(result).forEach(function (key) {
var row = result[key];
console.log(row.link)
if (row.link = req.params.link) {
if (i === 0) {
res.send(row.link + row.views + rows.created)
i = 1;
}
} else {
if (i === 0) {
res.send("URL does not exist")
i = 1;
}
}
});
});
});
A service that sends your data. You run into problems when you try to return your data in a loop. The good thing about this is to come back after you get all the result you will get from the loop. You can use asynchronous structure for this. Maybe you can try this.
router.get("/:link", (req, res) => {
let myObject = {};
connection.query(
"SELECT * FROM yourshort WHERE link = '" + req.params.link + "'",
async(err, result, rows, fields) => {
await Object.keys(result).forEach(function(key) {
var row = result[key];
if(row.link = req.params.link) {
myObject[key] = {link: row.link, views: row.views, created: rows.created}
return;
} else {
myObject['error'] = 'URL does not exist';
return;
}
});
await res.send(myObject);
});
});
I am trying to build login system using node.js and i am stuck in this call back function error i have managed to build get login info and check them with data base but when i am verifying password it's taking some time so in there i need to use call back function but even i used callback function it's giving me the same error which is since validation or database call taking time it's executing other stuff in the in my case if conditions.
i have tried to implement this another way just tried to console.log order and all executing opposite this my result first
this is the order that it's run
3
2
undefined
1
but i need run this exactly opposite should i use promises instead of callback?
const {ipcMain} = require('electron');
const Password = require("node-php-password");
const connection = require("./connection");
var hash;
var done;
var self = module.exports = {
getuser_information:function(user_name,pwd,callback){
connection.query("SELECT * FROM `super_admin` WHERE ad_un = ?", user_name, function(err, result, fildes) {
if (err) throw err;
let numbers_retuned = result.length;
hash = result[0].desk;
console.log(1);
});
callback(hash,self.true_or_not);
},
hashverif:function(hash,true_or_not){
true_or_not();
console.log(2);
},
true_or_not:function(){
console.log(3);
return 1
}
}
UPDATE after your comment
You have two errors
Your get_stored_password function returns nothing when your callback function is called that's why console.log(function_returning_nothing()) outputs undefined
You forgot to pass done to your callback function in
get_stored_password's definition callback(done)
const {
ipcMain
} = require('electron');
const Password = require("node-php-password");
const connection = require("./connection");
var hash;
var done;
var self = module.exports = {
get_stored_password: function(name, pwd, callback) {
connection.query("SELECT * FROM `super_admin` WHERE ad_un = ?", name, function(err, result, fildes) {
if (err) throw err;
let numbers_retuned = result.length;
hash = result[0].desk;
if (numbers_retuned == 1) {
var test = pwd;
done = Password.verify(test, hash);
} else {
console.log('no');
return 0;
}
//you must pass an argument to your callback function
// and return done var to get an output when you log this function
callback(done);
return done;
});
},
chek_if_true: function(done) {
console.log(done);
if (done) {
return true;
} else {
return false;
}
}
}
That's why when you log done to the console it's undefined
I am trying to generate a session ID when an API call is made to my 'generateSession' endpoint. I want to make sure that I don't have any duplicate session ID, so I query the database checking for a match on the generated ID. If there isn't a match, the ID is valid and I make a second query to add an active user with said session ID.
Although my first query executes, the 'id_is_valid' boolean never gets set to true so my program gets stuck in the while loop.
I am fairly new to JavaScript, but from some research, I'm pretty sure the problem is due to the asynchronous nature of the database call. However, I'm not sure where to go from there. Could anyone with more js knowledge offer me some direction?
Thanks!
var express = require('express');
var router = express.Router();
var myDB = require('../db-connection');
function generateSession() {
var session_id = '';
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (var i = 0; i < 30; i++) session_id += possible.charAt(Math.floor(Math.random() * possible.length));
return session_id;
}
router.get('/generateSession', function(req, res){
var session_id = '';
var id_is_valid = false;
while (!id_is_valid){
session_id = generateSession();
myDB.query("SELECT * FROM activeUser WHERE session_id = ?", [session_id], function(error, results, field){
if(error) throw error;
else{
if (results.length === 0) is_is_valid = true;
}
});
}
myDB.query("INSERT INTO activeUser (is_registered, session_id) VALUES (0, ?)", [session_id], function(error, results, fields){
if (error) res.send('{"success": false}');
else res.send('{"success": true, "session_id": "' + session_id + '"}');
});
});
Although my first query executes, the id_is_valid boolean never gets set to true so my program gets stuck in the while loop.
This is because db call, by nature is asynchronous. If you run the following program you will know it.
'use strict';
let id_is_valid = false;
let count = 0;
while (!id_is_valid) {
count++;
console.log(`No of time setTimeout Invoked ${count}`);
setTimeout(function() { // simulating a db call that takes a second for execution
id_is_valid = true;
}, 1000);
}
console.log('This line wont be printed');
Outputs
No of time setTimeout Invoked 61415
No of time setTimeout Invoked 61416
No of time setTimeout Invoked 61417
^C //I killed it.
Like damitj07, I too suggest using npms like shortId for uniquely generating the sessionId. This will help you to eliminate a database call.
But if your business logic restricts and you need it in the current fashion you wrote. I think we can use async & await
'use strict';
let isFound = false;
let count = 0;
function doDbQuery() {
return new Promise((resolve, reject) => {
setTimeout(function () {
resolve(true);
}, 2000);
});
}
async function run() {
while (!isFound) {
count++;
console.log(`No of time setTimeout Invoked ${count}`);
isFound = await doDbQuery();
}
console.log('This line WILL BE printed');
}
run();
Output
No of time setTimeout Invoked 1
This line WILL BE printed
Making those changes to your code,
router.get('/generateSession', async function (req, res) {
var session_id = '';
var id_is_valid = false;
while (!id_is_valid) {
session_id = generateSession();
id_is_valid = await checkSessionIdInDb(session_id);
}
myDB.query('INSERT INTO activeUser (is_registered, session_id) VALUES (0, ?)', [session_id], function (error, results, fields) {
if (error) {
res.send('{"success": false}');
} else {
res.send('{"success": true, "session_id": "' + session_id + '"}');
}
});
});
function checkSessionIdInDb() {
return new Promise((resolve, reject) => {
myDB.query('SELECT * FROM activeUser WHERE session_id = ?', [session_id], function (error, results, field) {
if (error) {
return reject(error);
} else {
if (results.length === 0) {
resolve(true);
}
resolve(false);
}
});
});
From what I could make out of your code what you want to do is basically create a new user session for logged in user with a unique session Id, also making sure that the session ID does not already exist in the collection.
So the solution to this can be to the first query to check if the session ID is already present in Active_Users Collection, if not make a save call to save the user with generated session Id.
var express = require('express');
var router = express.Router();
var myDB = require('../db-connection');
function generateSession() {
var session_id = '';
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (var i = 0; i < 30; i++) session_id += possible.charAt(Math.floor(Math.random() * possible.length));
return session_id;
}
router.get('/generateSession', function(req, res) {
var session_id = '';
myDB.query("SELECT * FROM activeUser WHERE session_id = ?", [session_id], function(error, results, field) {
if (error) {
throw error;
} else {
if (results.length === 0) {
//if session id is not present , insert new user
session_id = generateSession();
myDB.query("INSERT INTO activeUser (is_registered, session_id) VALUES (0, ?)", [session_id], function(error, results, fields) {
if (error) res.send('{"success": false}');
else res.send('{"success": true, "session_id": "' + session_id + '"}');
});
}
//else do nothing or inser nothing
}
});
});
But Ideally, if you are generating a truly random session id each time when you make a request to the /generate session, is it really necessary to check for duplicates in the collection.
Now if the logic to generate a random ID is not perfect, you can always use modules like shortId to do the work for you. This will avoid unnecessary database call and save on performance and your code will be much neater.
Considering that my server.js looks almost like this. Just send you the relevant part. I did not receive anything from the query, I do have data in the database, and "sendNotification" is triggered by the jQuery function in the client. Everything works and since var notis = []; returns an empty value and is what is shows as response. I know I have to debug SQL and that's what I'm going to do but anyway want to be sure of this other things. So my questions are:
1) Is a right syntax for node.js, considering this async behavior? (which I still don't understand )
2) The query always should be inside of the "io.sockets.on('connection')" part?
connection = mysql.createConnection({
host: 'localhost',
user: '',
password: "",
database: 'table' //put your database name
}),
...
connection.connect(function(err) {
// connected! (unless `err` is set)
console.log(err);
});
…
var sqlquery = function(uID,vs){
var notis = [];
connection.query("SELECT * FROM notification WHERE kid = ? AND v = ? ORDER BY id DESC",[uID,vs])
.on("result", function (data){
return notis.push(data);
});
};
io.sockets.on('connection', function(socket) {
...
socket.on("sendNotification", function(data) {
var roomBName = data.room_name.replace("room-",""),
found = [];
var roomSelected = _.find(rooms, function (room) { return room.id == roomBName });
for (var person in people) {
for (var i = 0, numAttending = roomSelected.peopleAttending.length; i < numAttending; i++) {
if (people[person].name == roomSelected.peopleAttending[i]) {
found.push(person);
}
}
}
for (var i = 0, numFound = found.length; i < numFound; i++) {
**result = sqlquery(9,2);**
io.to(found[i]).emit('notification', result);
};
});
Your sqlquery() function will not accomplish anything useful. Because connection.query() is asynchronous, that means it provides the response sometime LATER after sqlquery() has already finished.
The only way in node.js to use an async result is to actually use it in the callback that provides it. You don't just stuff it into some other variable and expect the result to be there for you in other code. Instead, you use it inside that callback or you call some other function from the callback and pass it the data.
Here's one way, you could change your sqlquery() function:
var sqlquery = function(uID, vs, callback){
connection.query("SELECT * FROM notification WHERE kid = ? AND v = ? ORDER BY id DESC",[uID,vs])
.on("result", function (data){
callback(null, data);
});
// need to add error handling here if the query returns an error
// by calling callback(err)
};
Then, you could use the sqlquery function like this:
found.forEach(function(person, index) {
sqlquery(..., function(err, result) {
if (err) {
// handle an error here
} else {
io.to(person).emit('notification', result);
}
});
});
And, it looks like you probably have similar async issues in other places too like in connection.connect().
In addition to #jfriend00, this could be done with new ES6 feature Promise :
var sqlquery = function(uID, vs){
return new Promise(function(resolve, reject){
connection.query("SELECT * FROM notification WHERE kid = ? AND v = ? ORDER BY id DESC",[uID,vs])
.on("result", function (data){
resolve(data);
});
});
};
Now you can use it like :
found.forEach(function(person, index) {
sqlquery(...)
.then(function(result){
io.to(person).emit('notification', result);
});
});