i have a problem regarding cross-file calls and their lifecycles. I want to query the dynamodb for a username to login the entered user.I query in an external file to minimize queries as i need to use the data in another file too. The cycle seems to be off though and I really don't know why. The query call comes after the POST / login although the input in the form is available earlier. It would print the queryparams before the POST/login call too if i'd call a console log on it. The callback does not wait for the actual data. I have browsed other posts containing information regarding asynchronous callback functions but couldn't figure out why the callback completely ignores the query function. The problem is not the communication between browser and server but rather between files/classes in the node script. The data is available for query before the post statement but the query gets executed after. This is What can i do to prevent that?
the console output (for debugging purposes) is:
GET /stylesheets/style.css 304 3ms
callback
undefined
POST /login 500 38ms - 280b
querying ...
information found
[queryResponse Object]
the query file:
const AWS = require("aws-sdk");
var exports = module.exports = {};
const dynamodb = new AWS.DynamoDB({
apiVersion: "2012-08-10",
// accessKeyId: "", //TODO
// secretAccessKey: "", //TODO
// region: "eu-central-1" //? TODO
//testing purposes
"region": "us-west-2",
"accessKeyId": "abcde",
"secretAccessKey": "abcde",
"endpoint": "http://localhost:8000"
});
var dataAfterQuery = null;
exports.query = function(queryParams,callback) {
/*prevent unneccessary queries*/
var queryNow = dynamodb.query(queryParams,
function(err,data) {
if(err) {
console.error(err);
return done(err);
}
console.log('querying ...');
if(data.Count > 0) {
console.log('information found');
} else {
console.log('"' + JSON.stringify(queryParams) + '" is not in the db yet');
}
dataAfterQuery = data;
console.log(JSON.stringify(dataAfterQuery));
return dataAfterQuery;
});
if(typeof callback == 'function') {
console.log("callback");
callback();
return queryNow;
}
}
/*function to recieve queried data*/
exports.getQueriedData = function() {
return dataAfterQuery;
}
the login file:
module.exports = function(passport) {
passport.use("login", new LocalStrategy({
passReqToCallback: true
},
function(req,username,password,done) {
var queryParams = {
TableName: "users",
KeyConditionExpression: "username = :user",
ExpressionAttributeValues: {
//username entered in jade form
":user":{"S":username}
}
};
queryFile.query(queryParams,function(err,data){
if(err) console.log(data);
//console.log(data);
//kommt vor information found?
console.error(data);
/* response can only be null or not null*/
if(data != null) {
console.error('error, more than one user with username: "' + username + '" in the db');
console.error("Entries :" + data.Count);
return done(null,false,req.flash("message", "more than version of the username in the db"));
} else {
//only one user exists in db, query for username was successful
var parsedQueryPw = data.Items[0].password.S;
userAfterQuery = data.Items[0];
//checking if entered password is wrong
if(!isValidPassword(parsedQueryPw, password)) {
console.error("invalid password");
return done(null,false,req.flash("message","invalid user-password combination"));
}
//successful login - user and password match
console.log("login successful");
//return user object for serialization
return done(null,data);
}
Related
I am trying to make a fetch in react.js using backend node.js api url which then further makes a post api call within the server to another route using another url.
How am i supposed to do that?
Take a look at the code below:
From the frontend "/confirm" api will be called using fetch.
app.post("/save-info",(req,res)=>{
//Does some more stuff and returns a
response to the confirm api.
}
app.post("/confirm", (req,res)=>{
//Does some stuff
//Makes another call inside this api
to the "/save-info" route
}
Updated Query
Guys, please take a look at the code below
async function signUp(info) {
const {
firstName,
lastName,
address,
email,
phoneNumber,
password,
city,
postal_code,
} = info;
console.log("only info: ", phoneNumber);
const queryInsertNewUser = `INSERT INTO public."Users"(
"First_Name", "Email", "Mobile", "Address", "User_Type", "Last_Name", "password", "city","postal_code")
VALUES ('${firstName}', '${email}', '${phoneNumber}', '${address}', 'Customer', '${lastName}', '${password}','${city}','${postal_code}')
RETURNING user_id;`;
// return { email: "kalo", id: "23" };
client.query(queryInsertNewUser, (err, result) => {
if (!err) {
if (result.rowCount == 1) {
console.log("User registered.");
return {
status: "Success",
msg: "User Registered Successfully",
user_id: result.rows[0].user_id,
};
} else {
console.log("Not Registered.");
return {
status: "Error",
msg: "Could not register user. Call Developer.",
};
}
} else {
console.log(err);
}
});
}
app.post("/signup", async(req, res) => {
const { email } = req.body;
const data = await signUp(req.body);
console.log(data);
});
data is printing undefined. Still it does not work
You don't need to call your route again. Just create an function and call it.
const saveInfo = ()=>{
// do wathever you want here
return "some stuff done"
}
app.post("/save-info",(req,res)=>{
// you probabbly don't need this route.
}
app.post("/confirm", (req,res)=>{
//Does some stuff
const data = saveInfo()
return res.send({success:true, done})
}
Trying to measure performance and output performance measures by using performance.getEntriesByType() however getting back an error that performance.getEntriesByType() is not a function. Tried different troubleshooting however anything I tried results in the same error, don't really understand how getEntriesByType() is not a function as it comes from a node dependency. Node version I am using is : 10.22.1 not using any npm packages pure NodeJs code.
var {performance} = require('perf_hooks');
var util = require('util');
var debug = util.debuglog('performance');
handlers._tokens.post = function (data, callback){
performance.mark('entered function')
var phone = typeof(data.payload.phone) == 'string' && data.payload.phone.trim().length > 10 ? data.payload.phone.trim() : false
var password = typeof(data.payload.password) == 'string' && data.payload.password.trim().length > 0 ? data.payload.password.trim() : false
performance.mark('inputs validated')
if (phone && password){
performance.mark('beginning user lookup')
_data.read('users', phone, function(err, userData){
performance.mark('user lookup complete')
if(!err && userData){
// hash the password and validate
performance.mark('beginning password hashing')
hashedPassword = helpers.hash(password)
performance.mark('password hashing complete')
if (hashedPassword == userData.hashedPassword) {
// if valid create token
performance.mark('creating data for token')
var tokenId = helpers.createRandomString(20)
// set expiry date
var expires = Date.now() + 1000 * 60 * 60
var tokenObject = {
'phone': phone,
'id': tokenId,
'expires': expires
}
performance.mark('token data creation complete')
performance.mark('beginning storing token data')
// store the token
_data.create('tokens', tokenId, tokenObject, function(err){
performance.mark('token data storing is complete')
// gather all the measurements
performance.measure('Beginning to end', 'entered function', 'token data storing is complete')
performance.measure('Password hasing', 'beginning password hashing', 'password hashing complete')
performance.measure('Finding user', 'beginning user lookup', 'user lookup complete')
performance.measure('Input validation', 'entered function', 'inputs validated')
performance.measure('Token creation', 'creating data for token', 'token data creation complete')
performance.measure('Token storing', 'beginning storing token data', 'token data storing is complete')
// log out all the measurements
var measurements = []
measuerments = performance.getEntriesByType('measure')
measurements.forEach((measurement)=>{
debug('\x1b(33m%s\x1b(0m', measurement.name + ' ' + measurement.duration)
})
if(!err){
callback(200, tokenObject)
} else {
callback(500, {'error': 'couldnt create new token'})
}
})
} else {
callback(400, {'error': 'passwords did not match'})
}
} else {
callback(400, {'error': 'couldnt find the user'})
}
})
} else {
callback(400, {'error': 'missing required fields'})
}
}
Have a look at the Documentation:
You need to create a PerformanceObserver and in its call back, you get a PerformanceObserverEntryList on which you can call getEntriesByType()
const {
performance,
PerformanceObserver
} = require('perf_hooks');
const obs = new PerformanceObserver((list, observer) => {
console.log(list.getEntriesByType('measure'));
observer.disconnect();
});
obs.observe({ entryTypes: ['measure'], buffered: true });
performance.measure('test');
(the code example is also taken from the documentation and slightly adapted to OP's question)
I tried sending a specific message to a client device using node js and firebase functions. But when I tried executing the function, it came back with an error saying:
Error. Registration token(s) provided to sendToDevice() must be a non-empty string or a non-empty array.
The image is shown below.
I was guessing it's from my JS code. So I am posting that too. What I am actually do is retrieving a data from a specific node to be used when a totally different node is being written. So I am gonna post the JS code before the database screenshots.
exports.sendNotification8 = functions.database.ref('/Users/{user_id}/Notifications/')
.onWrite(( change,context) =>{
var user_id = context.params.user_id;
// Grab the current value of what was written to the Realtime Database.
var eventSnapshot = change.after.val();
var device_token = admin.database().ref('/Users/{user_id}/device_token').once('value');
return device_token.then(result => {
var token_id = result.val();
var str = eventSnapshot.from + " : " + eventSnapshot.message;
console.log(eventSnapshot.from);
var payload = {
data: {
name: str,
title: eventSnapshot.from,
click_action: "Chats"
}
};
// Send a message to devices subscribed to the provided topic.
return admin.messaging().sendToDevice(token_id, payload).then(function (response) {
// See the MessagingTopicResponse reference documentation for the
// contents of response.
console.log("Successfully sent message:", response);
return;
})
.catch(function (error) {
console.log("Error sending message:", error);
});
});
});
And below is my database screenshots...
So that's how I am retrieving the device_token node. From the user that had the newest data written to his/her notifications node. Please help. What am I doing wrong?
Wow. This has been torture. But it finally worked. I got something like this.
exports.sendNotification8 = functions.database.ref('/Users/{user_id}/Notifications/{notifications_id}')
.onWrite((change,context) =>{
var user_id = context.params.user_id;
console.log(user_id);
// Grab the current value of what was written to the Realtime Database.
var eventSnapshot = change.after.val();
var device_token = admin.database().ref('/Users/'+user_id+'/device_token').once('value');
return device_token.then(result => {
var token_id = result.val();
console.log(token_id);
var str = eventSnapshot.message;
console.log(eventSnapshot.from);
var payload = {
data: {
name: str,
title: eventSnapshot.from,
click_action: "Chats"
}
};
// Send a message to devices subscribed to the provided topic.
return admin.messaging().sendToDevice(token_id, payload).then(function (response) {
// See the MessagingTopicResponse reference documentation for the
// contents of response.
console.log("Successfully sent message:", response);
return;
})
.catch(function (error) {
console.log("Error sending message:", error);
});
});
});
I am still a beginner in the Firebase world and I have been trying to figure out what the problem is with the below code but I failed in all possible ways.
The code is supposed to retrieve the uid from the user profile in the database, then use it to update the authentication profile, then again to update the database profile if the authentication profile update was successful.
In index.js I have defined an exported function to deal with POSTed params from HTML forms. The code below defines the handler function in another module file:
exports.auUpdateUserByEmail = (req, res) => {
// This handler function will retrieve the POSTed params of user profile
// and will attempt to update the existing user authentication as well as
// the database profiles.
//
// This function accepts the following params:
// 1. User email // 2. Phone number // 3. password // 4. Display name
// 5. Photo url // 6. Disabled Flag
//
var db = admin.firestore();
var uEmail = req.body.userEmail;
var dName = req.body.displayName;
var userId = "";
var newuser = {
displayName: dName
}
console.log("Email passed: " + uEmail);
// Fetch the user UID by user email...
res.write('User UID: ' + userId);
console.log('User UID: ' + userId);
// attempt to update the user authentication profile...
return db.collection('Users').where('email', '==', email).get()
.then(snapshot => {
snapshot.forEach(doc => {
var d = doc.data();
console.log("doc.id: " + doc.id + " - d.email: " + d.email);
if(d.email == email)
{
userId = d.uid;
}
});
return admin.auth().updateUser(userId, newuser);
}).then(function(userRecord) {
// The updating was successful... Attempt to update User Details in
// database User Profile...
console.log("User Updated Successfully. UID: " + userRecord.uid);
retUid = userRecord.uid;
// Create a reference to the Users Database...
var docRef = db.collection('Users');
// Update the user profile document.
return docRef.doc(userRecord.uid).update(newuser);
}).then(result => {
// everything went fine... return User UID as a successful result...
res.write(userId);
return res.end();
}).catch(function(error) {
console.log("doc.update - Error updating user profile in database:", error);
return res.end();
});
}
In index.js, I have the following exports definition:
var appAuth = express();
//Here we are configuring express to use body-parser as middle-ware.
appAuth.use(bodyParser.urlencoded({ extended: false }));
appAuth.use(bodyParser.json());
appAuth.post('/updateUserByEmail', authusers.auUpdateUserByEmail);
exports.usersAuthFunctions = functions.https.onRequest(appAuth);
I have to say that I got it to work fine to get the uid, update the auth profile, and then update database profile, but it keeps on waiting for the function return.
Appreciate your valuable help. Thanks.
I have updated the code as below and it does the jobs but returns a blank page as the HTTPS exits before the promises are complete which fires "Error: write after end" error.
var fetch_uid = db.collection('Users').where('email', '==', uEmail).get()
.then(snapshot => {
// var userId = snapshot.data.uid;
snapshot.forEach(doc => {
var d = doc.data();
console.log("doc.id: " + doc.id + " - d.email: " + d.email);
if(d.email == uEmail)
{
userId = d.uid;
res.write('User UID: ' + userId);
console.log('User UID: ' + userId);
}
});
return admin.auth().updateUser(userId, newuser);
}).then(function(userRecord) {
// The updating was successful... Attempt to update User Details in
// database User Profile...
console.log("User Updated Successfully. UID: " + userRecord.uid);
retUid = userRecord.uid;
// Create a reference to the Users Database...
var docRef = db.collection('Users');
// Update the user profile document.
return docRef.doc(userRecord.uid).update(newuser);
}).then(result => {
// everything went fine... return User UID as a successful result...
res.write(userId);
return;
}).catch(function(error) {
console.log("doc.update - Error updating user profile in database:", error);
return;
});
res.end();
A previous answer of mine on Cloud Functions for Firebase HTTP timeout might be of help here:
Cloud Functions triggered by HTTP requests need to be terminated by
ending them with a send(), redirect(), or end(), otherwise they
will continue running and reach the timeout.
From your code examples, it looks like your then(){} promise returns are ending with res.end(), but the entire function is returning the Promise from:
return db.collection('Users').where('email', '==', email).get()
Which could be stopping it from ending when you want it to. With HTTPS triggers, you don't need to return a Promise to keep the function running, only a result.
Try removing the return statement from this line:
db.collection('Users').where('email', '==', email).get()
Then you just need to ensure that all exit routes (or termination points) end with res.end() or similar, so currently you have 2 termination points:
}).then(result => {
// everything went fine... return User UID as a successful result...
res.write(userId);
res.status(200).end();
}).catch(function(error) {
console.log("doc.update - Error updating user profile in database:", error);
res.status(500).end();
});
Basically I'm getting an "Invalid" return when I try to verify a payment made using the IPN Listeners from Paypal and NodeJS, I'm sending back a urlencoded post back to paypal, for them to tell me whether it is valid or not, however it always returns Invalid.
I have a node app, and I'm using expressJS to manage all these server calls.
I already tried 2 different approaches:
app.post('/ipn', bodyParser.text({ type: 'urlencoded' }), function (req, res) {
res.sendStatus(200);
console.log('accedio al ipn');
//console.log(req.body);
var params = req.body;
ipn.verify(string, {'allow_sandbox': true}, function callback(err, msg) {
if (err) {
console.log(string);
console.error(err);
} else {
// Do stuff with original params here
if (params.payment_status == 'Completed') {
// Payment has been confirmed as completed
}
}
});
});
and
app.post('/ipn', bodyParser.text({ type: 'urlencoded' }), function (req, res) {
console.log('Received POST /');
console.log(req.body);
console.log('\n\n');
// STEP 1: read POST data
req.body = req.body || {};
res.status(200).send('OK');
res.end();
// read the IPN message sent from PayPal and prepend 'cmd=_notify-validate'
var postreq = 'cmd=_notify-validate';
for (var key in req.body) {
if (req.body.hasOwnProperty(key)) {
var value = querystring.escape(req.body[key]);
postreq = postreq + "&" + key + "=" + value;
}
}
// Step 2: POST IPN data back to PayPal to validate
console.log('Posting back to paypal');
console.log(postreq);
console.log('\n\n');
var options = {
url: 'https://www.sandbox.paypal.com/cgi-bin/webscr',
method: 'POST',
headers: {
'Connection': 'close'
},
body: postreq,
strictSSL: true,
rejectUnauthorized: false,
requestCert: true,
agent: false
};
request(options, function callback(error, response, body) {
if (!error && response.statusCode === 200) {
// inspect IPN validation result and act accordingly
console.log(body);
if (body.substring(0, 8) === 'VERIFIED') {
// The IPN is verified, process it
console.log('Verified IPN!');
console.log('\n\n');
// assign posted variables to local variables
var item_name = req.body['item_name'];
var item_number = req.body['item_number'];
var payment_status = req.body['payment_status'];
var payment_amount = req.body['mc_gross'];
var payment_currency = req.body['mc_currency'];
var txn_id = req.body['txn_id'];
var receiver_email = req.body['receiver_email'];
var payer_email = req.body['payer_email'];
//Lets check a variable
console.log("Checking variable");
console.log("payment_status:", payment_status)
console.log('\n\n');
// IPN message values depend upon the type of notification sent.
// To loop through the &_POST array and print the NV pairs to the screen:
console.log('Printing all key-value pairs...')
for (var key in req.body) {
if (req.body.hasOwnProperty(key)) {
var value = req.body[key];
console.log(key + "=" + value);
}
}
} else if (body.substring(0, 7) === 'INVALID') {
// IPN invalid, log for manual investigation
console.log('Invalid IPN!');
console.log('\n\n');
}
}
});
});
Both of them return Invalid.
First example is taken from:
https://github.com/andzdroid/paypal-ipn
Second one is taken from:
https://github.com/HenryGau/node-paypal-ipn
As far as I know, I receive a payment notification using IPN on my server, then I resend that request to Paypal so I can verify it it's valid or not, for security purposes, this is all done within the sandbox environment.
I also tried to send the request I get, but this time using POSTMAN, and it also returns Invalid, been stuck here for a while.
Note: I'm trying to use this for suscription payments, I don't know if this is relevant or not, just in case.