Node.js Knex SQL insert is too slow - javascript

I have a basic login system that does the following:
Checks if the username exists (goes OK)
Inserts the username
After the insert, I select the id of the inserted username. This goes correct on the first login, but when I logout and login with a new username, the insert is too slow, causing my select to throw an exception, because the insert is not done yet. How can I fix this?
My code:
Database.js:
getPlayerByName (username) {
return this.knex("penguins").first("*").where("username", username)
}
getPlayerExistsByName (username) {
return this.knex("penguins").where("username", username).select("username")
}
insertPlayer (username) {
return this.knex("penguins").insert({username: username}).then(() => {
Logger.info(`Inserted ${username}`)
}).catch((err) => {
Logger.error(err)
})
}
Login.js:
function handlePlayer (username, res) {
database.getPlayerExistsByName(username).then(result => {
if (result.length != 1) { // Username does not exist
database.insertPlayer(username) // Insert username
database.getPlayerByName(username).then(penguin => {
return write(`&id=${penguin.id}&m=${penguin.mod}${Errors.OK}`, res) // I need the id here
})
} else {
return write(Errors.NAME_UNAVAILABLE, res)
}
})
}

Try to use async funcion in the callback of then and use await in insert and get user to do this 2 methods synchronous

Related

How to make a post request by SERVER not by user

Node.js CODE
exports.user = async (req, res) => {
try {
const { wallet } = req.body;
if (!wallet) {
res.status(400).json({ error: "Not logged in" });
return;
} else {
user = User.findone(wallet);
// if user is not found then create a new user and mark as loggged In
if (!user) {
User.create({
user: wallet,
});
}
// if user found then create a session token and mark as logged
in
res.send({
user: wallet,
});
}
} catch (error) {
console.log(`ERROR::`, error);
}
};
REACTJs CODE
// post call/update
const axiosCall = async () => {
// core login will give a unique username by fulling a transcation
// core.login i dont have any control
const userAccount = await core.login();
try {
const res = await Axios.post(`${API}/user`, userAccount, dataToken);
setData({
...data,
error: "",
success: res.data.message,
});
} catch (error) {
setData({
...data,
error: error.response.data.error,
});
}
};
Now here the problem occurs when some one could modify userAccount in the front-end or someone could send a body with wallet: anything to my route localhost:3000/api/user
There is no option for me to check if some actually used core.login(); to get the wallet address.
So is there any solution?
I was thinking to allow only my server IP or localhost to hit the route localhost:3000/api/user and is that even possible?
Also there is another issue anyone could modify userAccount in front-end.

Keep getting invalid credentials when login node.js + Express.js

I am fairly new to node.js and trying to get my login credentials from the database, I can successfully get login credentials from the database but when I call it from my server.js file, I keep getting Invalid credentials even though they are the right credentials. I will appreciate it if fresh eyes could look into this and point out what I am doing wrong. Using Postgres DB
app.post('/api/login', async (req, res) => {
try {
const loginCredentials = {
email: req.body.email,
password: req.body.password
}
if (loginCredentials.email === '' && loginCredentials.password === '') {
return res.status(500).send('Email and Password required')
}
if (loginCredentials.email === '' || loginCredentials.password === '') {
return res.status(500).send('Email and Password required')
}
if (loginCredentials.email && loginCredentials.password ) {
// getting credentials from db.login
const result = await db.login(loginCredentials.email, loginCredentials.password)
console.log('* ' + result)
if (result) {
res.status(200).send("Success")
} else {
res.status(401).send("Invalid Credentials")
}
}
} catch (e) {
throw e
}
and here is my db.login method
async function login(email, password) {
console.debug("login db")
const query = `SELECT *
FROM users
WHERE email = $1`
const client = await pool.connect()
try {
await client.query(query, [email], async function (err, result) {
if (err) {
throw err
}
console.debug('hash: ' + result.rows[0].hash)
console.debug('pass: ' + password)
if (result.rows.length > 0) {
const user = result.rows[0]
//role = user.role
const validPassword = bcrypt.compare(password, user.hash)
if (!validPassword){
console.log('Invalid Credentials')
return 'Invalid Credentials'
}else {
console.debug('success')
return user
}
} else {
return 'No user in the DB'
}
})
} catch (e) {
throw e
}
}
You are not awaiting the compare method's result, so validPassword will always be an unresolved Promise, not the result.
Adding await should fix it:
const validPassword = await bcrypt.compare(password, user.hash)
EDIT: I see you check with if (!validPassword), which is never "truthy" if validPassword is a Promise. You might want to check what version of bcrypt you are using - does compare return a Promise, or is this maybe an old version that uses a callback signature only. In that case you should either update your bcrypt dependency, or use the callback method instead: compare(password, user.hash, function(err, validPassword) { /* check validPassword here */ }).
You might also want to check your flow, you return the user from the client.query callback, but you are also awaiting it, but not storing or returning its return value. I have no experience with the Postgres API, but it looks like you are mixing Promises (with async/await) and callbacks. In my experience it's always one or the other - you either use the callback flow, or returned Promise flow. If client.query returns a Promise, it will probably resolve with the results you are now handling with the callback.
Try rewriting it this way:
async function login(email, password) {
console.debug("login db")
const query = `SELECT *
FROM users
WHERE email = $1`
const client = await pool.connect()
try {
const result = await client.query(query, [email])
console.debug('hash: ' + result.rows[0].hash)
console.debug('pass: ' + password)
if (result.rows.length > 0) {
const user = result.rows[0]
//role = user.role
const validPassword = await bcrypt.compare(password, user.hash)
if (!validPassword){
console.log('Invalid Credentials')
return 'Invalid Credentials'
}else {
console.debug('success')
return user
}
} else {
return 'No user in the DB'
}
} catch (e) {
throw e
}
}
Another edit: Notice that the code above will now actually return something, either the user row or a string. Previously, your db.login method returned a Promise that resolved without a value, always failing your following if (result) check because result is undefined. If you change your db.login code to the above, the if (result) will now always be true because it is either a string or the user object. You might want to throw 'Invalid credentials' and throw 'No user in the DB' instead, and wrap the db.login(..) call in try / catch:
try {
const result = await db.login(loginCredentials.email, loginCredentials.password)
res.status(200).send("Success")
}
catch(err) {
res.status(401).send("Invalid Credentials")
}

Res value is null in an app.get call done from vue.js front-end to express back-end

I am calling this code from the front-end and confirmed that there is a proper db connection and that the Id value is properly passed, and that there is a corresponding value in the database, but for some reason, res is null. What am I missing?
app.get("/api/walletlogin/user/:userId", (req, res) => {
id = req.params.userId
var query = {_id: id}
db.collection("Users").findOne(query, (err, result) => {
if (result) {
console.log(result.userName)
} else {
console.log('No User')
}
})
Here is the front-end call:
axios.get('/api/walletlogin/user/' + accounts)
.then((response) => {
console.log('Logged in With ' + accounts)
router.push('/account')
})
.catch((errors) => {
console.log('Cannot log in')
})
}).catch((err) => {
console.log(err, 'err!!')
})
You could try to convert your id to an objectID.
var ObjectId = require('mongodb').ObjectId;
var id = ObjectId(req.params.userId);
to search by id, you must use the ObjectID class from the mongodb package. Here is an example invented by me, it does not reflect the real work, but I hope it will become clear on it:
const { ObjectID } = require('mongodb');
const id = '5ee4f69bfa0b960de8aec158'; // in your example is req.params.userId
db.collection('users').findOne({ _id: new ObjectID(id)}, (error, result) => {
if (error) {
throw error;
}
console.log(result);
})
I am adding the details of the issue initially encountered in case someone else would experience it in the future. The value that is passed from the front-end is a cryptocurrency address. For some reason, some of the characters passed were upper-case, while the same address had been stored in the database with these same characters as lower case. Thus, one needs to add code to make sure that the case of the letters found in the respective addresses is ignored.
J

nodejs callback: doesn't detect any errors, just like if there were no error at all

Node js/Javascript doesn't catch the error while querying mysql server
The nodejs server queries the submittedName from form, checks the database along with submittedName. If submittedName matches with the submittedName, renders success. If it doesn't match, it should render notfound.
But indeed, it does not. Instead, it renders success. Even on wrong input.
app.post("/whatisyourname", (req, res) => {
var submittedName = req.body.details;
console.log(details);
//query the mysql database
conn.query(
"SELECT * FROM giftapp where name= ?",
submittedName,
(err, rs) => {
//handle the error
if (err) {
console.log(err);
//while it should render the "notfound" file,
//it renders "success"
res.render("notfound");
} else {
//if no error, render success
res.render("success", { myR: rs[0] });
}
}
);
I expect to be forwarded to "notfound" in case of wrong input or just any error
And to be forwarded to "success" in case of correct input
The express server or sql connection or callback won't throw any error in this case. You will get an error if something goes wrong while querying the db, i.e Invalid query or connection error etc. In your case the query executes successfully and gives you the result which is an empty array. You need to manually check and return the result. Change your code like:
app.post("/whatisyourname", (req, res) => {
const submittedName = req.body.details;
console.log(details);
//query the mysql database
conn.query(
"SELECT * FROM giftapp where name= ?",
submittedName,
(err, results) => {
if (err) {
console.log(err);
res.render("notfound");
} else {
if (results && results.length > 0) {
res.render("success", { myR: results[0] });
} else {
res.render("notfound");
}
}
});
});
Hope this helps :)
var submittedName = req.body.details;
var sql = 'SELECT * FROM giftapp WHERE name = ?';
con.query(sql, [submittedName], function (err, result) {
if (err) res.render("notfound"); // if you view is called notfound.ejs remove the space between not and found.
console.log(result);
res.render("success", { myR: result[0] }); // need success.ejs
});

ExpressJS variable undefined

I have an ExpressJS app that when a user makes a POST request to a route, it should lookup the ID in the MongoDB using req.params.formId
I have some console.log statements tfor debugging and so I can see what info is being returned.
The route should lookup the ID passed and when it finds it, use the req.body data and also a field from the MongoDB document but this just seems to return as undefined
Here is the code for the route:
app.post("/api/v1/forms/:formId", (req, res) => {
const { name, email, message } = req.body;
console.log(req.body);
Form.findById(req.params.formId, Form.recipient, err => {
if (err) {
res.send(err);
} else {
const formRecipient = Form.recipient;
const newForm = {
name,
email,
message,
recipient: formRecipient
};
console.log(newForm);
const mailer = new Mailer(newForm, contactFormTemplate(newForm));
try {
mailer.send();
res.send(req.body);
} catch (err) {
res.send(err);
}
}
});
});
So an example, if I make a POST request to localhost:5000/api/v1/forms/5ad90544883a6e34ec738c19 the console.log of newForm shows { name: ' Mr Tester',
email: 'person#example.com',
message: 'Hi there',
recipient: undefined }
The forms Mongoose schema has a field named recipient
the correct way is to provide the fields you want to get as the second argument:
Form.findById(req.params.formId, 'recipient', (err, form) => {
if (err) {
// error handling code
} else {
const formRecipient = form.recipient;
}
...
});
here's the Docs

Categories