azure mobile api variable scope - node.js

I have the following Azure Mobile Services API get function. I want to set the isValidUser flag based on if there is a record for the providerKey (from the twitter authentication) in the SQLMembership table (AspNetUserLogins).
While testing, I see the following in the log file, confirming that the flag is being set.
"setting isValidUser [object Object] Number of records = 1"
However, if(isValidUser) is not getting evaluated correctly. The result I get from the API is "Not a registered user." which is set from the else portion of the if(isValidUser) check.
Why is it that the value set inside the mssql.query() is not available outside of it?
exports.get = function(request, response) {
var authenticatedUserId = request.user.userId;
var providerName = authenticatedUserId.split(":")[0];
var providerUserId = authenticatedUserId.split(":")[1];
var isValidUser = false;
console.log('providerName = ' + providerName.trim());
console.log('providerUserId = ' + providerUserId.trim());
request.service.mssql.query(
"select userId from dbo.AspNetUserLogins where LoginProvider = '" + providerName + "' and ProviderKey = '" + providerUserId + "'",
{
success: function(results)
{
console.log('inside success AspNetUserLogins. ' + results + " Number of records = " + results.length);
if (results.length == 1) {
console.log('setting isValidUser ' + results + " Number of records = " + results.length);
isValidUser = true;
}
},
error : function(err)
{
console.log('inside error AspNetUserLogins. ' + err);
response.send(statusCodes.INTERNAL_SERVER_ERROR, { error: err });
}
}
);
if (isValidUser) {
request.service.mssql.query('select * from dbo.Church',
{
success: function(results)
{
console.log('inside success Church' + results);
response.json(statusCodes.OK, results);
},
error : function(err)
{
console.log('inside error : ' + err);
response.send(statusCodes.INTERNAL_SERVER_ERROR, { error: err });
}
}
);
} else {
response.send(statusCodes.INTERNAL_SERVER_ERROR, { error: "Not a registered user." + isValidUser });
}
response.send(statusCodes.INTERNAL_SERVER_ERROR, { error: "Unexpected end." });
};

The call to mssql.query is an asynchronous function (like many other functions in node.js); when it returns the callback (either the success or the error) hasn't been executed yet, so when you check the isValidUser flag, it still has the original value (false).
What you need to do is to move that code to inside the success callback, and that should work:
exports.get = function(request, response) {
var authenticatedUserId = request.user.userId;
var providerName = authenticatedUserId.split(":")[0];
var providerUserId = authenticatedUserId.split(":")[1];
var isValidUser = false;
console.log('providerName = ' + providerName.trim());
console.log('providerUserId = ' + providerUserId.trim());
var sql = "select userId from dbo.AspNetUserLogins where LoginProvider = ? and ProviderKey = ?";
var sqlParams = [providerName, providerUserId];
request.service.mssql.query(sql, sqlParams, {
success: function(results)
{
console.log('inside success AspNetUserLogins. ' + results + " Number of records = " + results.length);
if (results.length == 1) {
console.log('setting isValidUser ' + results + " Number of records = " + results.length);
isValidUser = true;
}
if (isValidUser) {
request.service.mssql.query('select * from dbo.Church', {
success: function(results)
{
console.log('inside success Church' + results);
response.send(statusCodes.OK, results);
},
error : function(err)
{
console.log('inside error : ' + err);
response.send(statusCodes.INTERNAL_SERVER_ERROR, { error: err });
}
});
} else {
response.send(statusCodes.INTERNAL_SERVER_ERROR, { error: "Not a registered user." + isValidUser });
}
},
error : function(err)
{
console.log('inside error AspNetUserLogins. ' + err);
response.send(statusCodes.INTERNAL_SERVER_ERROR, { error: err });
}
});
};
One more thing: do use parameters in the SQL (also shown above), instead of composing the query directly. In this case (you're using the user id) it shouldn't be a problem, but as a general rule you should use parameters whenever possible to prevent SQL injection attacks.

Related

Requesting URL's one by one

I'm trying to get some data from a lot of URLs using 'request', but I can't manage to do it one url at a time.
I've tried to understand async/promises in order to make it work, but with no success. Trial and error didn't work.
I've seen other methods using different modules, but this requires rewriting most of my code and I believe there is an easier way to adapt it to my current code.
Here is a minimized version of the code :
const request = require('request');
const fs = require('fs');
const prod = fs.readFileSync('prod.txt', "utf8");
const prodid = prod.split("|");
var i;
var summary=[];
for (i=0;i<prodid.length;i++){
request('https://www.api.example.com/id='+prodid[i], { json: true }, (err, res, body) => {
if (err) { return console.log(err); }
if (body == 'NULL') {
console.log("Page " + i + " out of " + prodid.length + " is NULL!");
} else {
summary.push(body.items[0].Name);
summary.push(body.items[0].ISOnr);
summary.push(body.items[0].GTIN);
console.log("Page " + i + " out of " + prodid.length + " is done!");
fs.appendFileSync('data.txt',JSON.stringify(summary));
}
});
}
There is no async/promise involved in the example above, just the requests inside a loop.
From what I've seen, when I get the results, there is no particular order (probably is the order of which finishes first).
In the console, I always see page 500 out of 500, not 1/500, 2/500, etc.
What I'm trying to achieve, is by making each request in the order of URLs (preferably with a 1000ms delay between them)
You can promisify your request:
for (i = 0; i < prodid.length; i++) {
const result = await new Promise((resolve, reject) =>
request(
'https://www.api.example.com/id=' + prodid[i],
{ json: true },
(err, res, body) => {
if (err) {
reject(err);
}
if (body == 'NULL') {
console.log('Page ' + i + ' out of ' + prodid.length + ' is NULL!');
} else {
resolve(body);
}
}
)
);
if (result) {
summary.push(result.items[0].Name);
summary.push(result.items[0].ISOnr);
summary.push(result.items[0].GTIN);
console.log('Page ' + i + ' out of ' + prodid.length + ' is done!');
fs.appendFileSync('data.txt', JSON.stringify(summary));
}
}

LDAP authentication using ldapjs in nodejs

Am a newbie to node.js, have somewhat figured out the LDAP authentication. Here am trying to retrieve employee ID from the search but none of the search entries are fetched though the passed credentials are bounded successfully , not sure where i'm mislead. If someone could help me out in it would be of a great help!
Below are the result sets of the code snippet:
Reader bind succeeded
Search results length: 0
Search
retval:{"messageID":2,"protocolOp":"LDAPResult","status":0,"matchedDN":"","errorMessage":"","referrals":[],"controls":[]}
No unique user to bind
ldapRoute.route('/ldap').post((req, res, next) => {
var result = "";
var email =req.body.email;
var client = ldap.createClient({
url: 'ldap://******'
});
var opts = {
filter: '(sAMAccountName='+ email + ')',
attributes: ['sAMAccountName']
};
var username = 'ii' + "\\" + email;
client.bind(username, req.body.password, function(err) {
if (err){
result += "Reader bind failed " + err;
res.send(result);
return;
}
else{
result += "Reader bind succeeded\n";
}
client.search('OU=emp,dc=i,dc=ac,dc=com', opts, function(err, searchRes) {
var searchList = []
if (err) {
result += "Search failed " + err;
res.send(result);
return;
}
searchRes.on("searchEntry", (entry) => {
result += "Found entry: " + entry + "\n";
searchList.push(entry);
});
searchRes.on("error", (err) => {
result += "Search failed with " + err;
res.send(result);
});
searchRes.on("end", (retVal) => {
result += "Search results length: " + searchList.length + "\n";
for(var i=0; i<searchList.length; i++)
result += "DN:" + searchList[i].employeeID + "\n";
result += "Search retval:" + retVal + "\n";
if (searchList.length == 1) {
client.bind(searchList[0].employeeID, req.body.password, function(err) {
if (err)
result += "Bind with real credential error: " + err;
else
result += "Bind with real credential is a success";
res.send(result);
}); // client.bind (real credential)
} else {
result += "No unique user to bind";
res.send(result);
}
});
});
});
});
The issue was in the filters and for some strange reasons the 'end' got fired before hitting the 'searchEntry', debugging it helped me to resolve the issue.
//Filter
var opts = {
filter: '(sAMAccountName=' + email+')',
scope: 'sub',
attributes: ['employeeID']
};
//Search
client.search('OU=empl,dc=ii,dc=ac,dc=in', opts, function(err, searchRes)
{
if (err)
{
result += "Search failed " + err;
res.send(result);
return;
}else{
searchRes.on("searchEntry", (entry) =>
{
result += "Found entry: " + entry.object.employeeID;
res.send(result);
}
/ ........../
} });

Getting Response of a function defined in another file in node.js

I have a socket function defined as
var funcs = require('./funcs');
socket.on(EVENT_ACCEPT_ORDER, function(data, callback)
{
data = JSON.parse(data);
var bookingId = data.bookingId;
var userId = data.userId;
console.log("Accepting booking...." + bookingId);
var query = "UPDATE bookings SET bookingStatus = " + BOOKING_STATUS_ACCEPTED + " WHERE id = " + bookingId + " AND bookingStatus = " + BOOKING_STATUS_IN_QUEUE;
con.query(query, function(err, rows,fields)
{
if(err)
{
console.log("mysql query error");
}
else
{
if(rows.changedRows > 0)
{
var indexOfUser = usersList.indexOf(userId);
if(indexOfUser > -1)
{
userSockets[indexOfUser].emit(EVENT_USER_ORDER_ACCEPTED);
}
callback({"message": "Success","error":false, "booking": funcs.getBooking(con, bookingId)});
}
else
callback({"message": "Success","error":true});
}
});
});
Funcs is defined as
module.exports = {
"getBooking": function (con, bookingId)
{
var query = "SELECT * FROM bookings WHERE id = " + bookingId + " LIMIT 1";
con.query(query, function(err, rows,fields)
{
if(err)
{
console.log("mysql query error");
}
else if (rows.length == 1)
{
var booking = rows[0];
var userId = rows[0]['userId'];
var query = "SELECT id, name, phone, imagePath FROM users WHERE id = " + userId + " LIMIT 1";
con.query(query, function(err, rows,fields)
{
if(err)
{
console.log("mysql query error");
}
else if (rows.length == 1)
{
booking['user'] = rows[0];
return booking;
}
});
}
});
}
}
Everything is running fine except
callback({"message": "Success","error":false, "booking": funcs.getBooking(con, bookingId)});
in this function instead of booking, i am only getting
{"error":false,"message":"Success"}
Why am i not getting the booking function result?
You are not getting the result, because the result of the callback function in con.query is not returned to the caller of getBooking. It is the asynchronous pattern, which you are not processing correctly.
The way it is supposed to work is that the getBooking gets an extra argument: a function to be called when data are available (in an internal asynchronous call to con.query). Such a function is then provided by the caller and in this function you do whatever you want with the data:
funcs.js
"getBooking": function (con, bookingId, callback) {
...
con.query(query, function(err, rows,fields) {
...
// instead of return booking do
callback(err, booking);
...
}
}
main module
// instead of
callback({"message": "Success","error":false, "booking": funcs.getBooking(con, bookingId)});
// do
funcs.getBooking(con, bookingId, function(err, booking) {
callback({"message": "Success","error":false, "booking": booking});
});
I am afraid this is not the only issue in your code, but this should be the first to fix. Read further about processing asynchronous calls in general and specifically in node.js and fix other places in your code correspondingly.

NODE.JS function callback to render page

I have a function getthem() that checks a mongo db for listings and returns name,streamurl for it.
I pass those as var stream to the renderme that renders the /dashboard page.
My problem is that i get the console.log("END OF FIND:"+JSON.stringify(stream))
to show my test input, but nothing goes to the render.
im using ejs to render. How can i get the result passed to the page ?
router.get('/dashboard', function (req, res) {
var foo = getthem();
function getthem() {
var group = "tesint";
console.log('geting for group : ' + group);
var mdlListings = require('../models/listings.js');
var myresult = "tet";
mdlListings.find({}, "name streamurl", function (err, data) {
if (err) {
console.error(err);
return;
}
if (data === null) {
console.log("No results");
return;
}
var stream = { };
data.forEach(function (streams) {
console.log("Got " + streams.name + " " + streams.streamurl);
stream[streams.name] = streams.streamurl;
// stream += 'name: '+streams.name+'},{streamurl: '+streams.streamurl;
// console.log("stram arry "+stream[streams.name] )
console.log("END OF FIND:"+JSON.stringify(stream))
}, renderme(stream));
// console.log("Result:", votes);
//var myresult = Object.keys(stream).map(function (name) {
// return { name: name, url: stream[name] };
//})
console.log("before return stream "+stream);
return stream;
});
}
function renderme(resa) {
console.log("RESA"+JSON.stringify(resa))
var resa = JSON.stringify(resa);
res.render('dashboard', {
title: 'Dashboard',
user: req.user,
listing: resa
}
)
}
You're passing the result of renderme(stream) as a second argument to forEach(). renderme(stream) is then evaluated immediately before your forEach() callback is called, when stream is still an empty object. My guess is you want something like this:
data.forEach(function (streams) {
console.log("Got " + streams.name + " " + streams.streamurl);
stream[streams.name] = streams.streamurl;
console.log("END OF FIND:"+JSON.stringify(stream))
});
renderme(stream);
Actually i figure that why would i pass the function as i could just do whatever i need to directly in there.
That worked perfectly, thanks for the tip.
data.forEach(function (streams) {
console.log("Got " + streams.name + " " + streams.streamurl);
stream[streams.name] = streams.streamurl;
});
res.render('dashboard', {
title: 'Dashboard',
user: req.user,
listing: data
}
)

ServiceNotAvailableError: Failed to register SAAgent

I'm developing an integrated Gear 2 App and I have some issues with the connection between the phone and Gear 2. The problem is when I call the function:
webapis.sa.requestSAAgent(onsuccess, onerror);
In the console I have this log: ONERROR: err [ServiceNotAvailableError] msg [Failed to register SAAgent.]
The problem is that the functions instantly go to the onerror function, jumping the onsucces function. I post my code for clarification:
function onerror (err) {
console.log("ONERROR: err [" + err.name + "] msg [" + err.message + "]");
}
var agentCallBack = {
onconnect: function (socket) {
console.log ("agentCallBack onconnect" + socket);
SASocket = socket;
alert("SAP Connection Establishe with RemotePeer");
createHTML("startConnection");
SASocket.setSocketStatusListener(function(reason) {
console.log ("Service connection lost, Reason: [" + reason + "]");
disconnect();
})
},
onerror : onerror
};
var peerAgentFindCallback = {
onpeeragentfound : function(peerAgent) {
try {
if (peerAgent.appName == ProviderAppName) {
SAAgent.setServiceConnectionListener(agentCallback);
SAAgent.requestServiceConnection(peerAgent);
} else {
alert("Not expected app!! : " + peerAgent.appName);
}
} catch(err) {
console.log("exception [" + err.name + "] msg[" + err.message + "]");
}
},
onerror : onerror
}
function onsuccess(agents) {
try {
if (agents.length > 0) {
SAAgent = agents[0];
SAAgent.setPeerAgentFindListener(peerAgentFindCallback);
SAAgent.findPeerAgents();
} else {
alert("Not found SAAgent!!");
}
} catch(err) {
console.log("exception [" + err.name + "] msg[" + err.message + "]");
}
}
Anyone can explain how can I fix this? I've already put this privilege into the config.xml file:
<tizen:privilege name="http://developer.samsung.com/privilege/accessoryprotocol"/>
It sound like you are missing serviceprofile.xml file. You need that in both phone and gear applications.
Here is samsung developer guide: http://pl.scribd.com/doc/231769842/Samsung-Gear-Application-Getting-Started-1-0
Look into section 5.2.

Resources