Try catching a variable passed in from res.render - javascript

I am executing a try catch block within a script tag on my ejs webpage.
My server renders the page sometimes with the token & user, and sometimes without. Each time I passed through a variable I would do the var x = <%- JSON.stringify(x) %>;. This time I did it, since there was nothing passed in, it gave me an error.
This is not the issue. The issue I am running into is that it does not seem to work! See the below code:
try {
var Token = <%- JSON.stringify(Token) %>;
var User = <%- JSON.stringify(User) %>;
}
catch(err){
console.log("there is no token/user");
}
I want for my code to try to initlize these variables, if they were passed in from the res.render function from the server. If they were not passed in, no problem, just continue on.

You can't use try/catch to detect a syntax error.
Instead, you could give a default value in case the variables aren't set.
var Token = <%- JSON.stringify(Token || "") %>;
var User = <%- JSON.stringify(User || "") %>;
if (Token == "" || User == "") {
console.log("there is no token/user");
}

var tokenexist = false;
var userexist = false;
<% if (Token) {
tokenexist = true;
}
if (User) {
userexist = true;
} %>
if (userexist && tokenexist) {
var Token = '<% - JSON.stringify(Token) %>';
var User = '<% - JSON.stringify(User) %>';
} else {
console.log("there is no token/user");
}

Related

Is it invalid to write re.send() function inside mydb.collection().find().toArray callback?

I'am setting up a login page for my app. I want to send a file after verifing if the login page is provided with proper username and password.
I have a handler for a post request which checks if the user entered correct username and password.
app.post('/login',function(req,res){
var data="";
var flag_isthere=0,wrongpass=0;
console.log('login-done');
req.setEncoding('UTF-8')
req.on('data',function(chunk){
data+=chunk;
});
req.on('end',function()
{
MongoClient.connect("mongodb://localhost:27017/userdetails",{useNewUrlParser: true ,useUnifiedTopology: true },function(err,db)
{
if(err) throw err;
var q = JSON.parse(data)
const mydb=db.db('userdetails')
var c=mydb.collection('signup').find().toArray(
function(err,res)
{
for(var i=0;i<res.length;i++)
if( (res[i].email==q['email']) ) //check if the account exists
{
flag_isthere=1;
if( (res[i].pass != q['pass'] ) )
wrongpass=1;
break;
}
if(flag_isthere==0)
{
console.log(q['email'], ' is not registered')
}
else
{
console.log('Already exists!!!');
}
if( wrongpass==1)
{
console.log('password entered is wrong')
}
if(flag_isthere==1 && wrongpass==0)
{
console.log('Congratulations,username and password is correct');
res.send( { login:'OK', error:'' } ); //this statement is giving an error in node JS part
}
});//var c
})//mongoclient.connect
})//req.on
res.send({ login:'OK', error:'' }); //this works properly in node JS
console.log(flag_isthere , wrongpass ) //but here the flag_isthere==0 and wrongpass==0 , so it won't get validated
});
It gives the error as
TypeError: res.send is not a function
at E:\ITT_project_shiva\loginserver_new.js:112:25
at result (E:\ITT_project_shiva\node_modules\mongodb\lib\operations\execute_operation.js:75:17)
at executeCallback (E:\ITT_project_shiva\node_modules\mongodb\lib\operations\execute_operation.js:68:9)
at handleCallback (E:\ITT_project_shiva\node_modules\mongodb\lib\utils.js:129:55)
at cursor.close (E:\ITT_project_shiva\node_modules\mongodb\lib\operations\to_array.js:36:13)
at handleCallback (E:\ITT_project_shiva\node_modules\mongodb\lib\utils.js:129:55)
at completeClose (E:\ITT_project_shiva\node_modules\mongodb\lib\cursor.js:859:16)
at Cursor.close (E:\ITT_project_shiva\node_modules\mongodb\lib\cursor.js:878:12)
at cursor._next (E:\ITT_project_shiva\node_modules\mongodb\lib\operations\to_array.js:35:25)
at handleCallback (E:\ITT_project_shiva\node_modules\mongodb\lib\core\cursor.js:32:5)
[nodemon] app crashed - waiting for file changes before starting...
How do I send the response to the user after proper validation?
It's not that you're doing it from the callback that's the problem. There are two different problems:
You're shadowing res by redefining it in the callback's parameter list
(Once you fix that) You're calling res.send twice:
Once at the end of your posthandler
Once within the callback
send implicitly completes the response, so you can only call it once.
In your case, you want to call it from within your callback, once you've determined that none of the records matches.
See *** comments for a rough guideline (but keep reading):
app.post('/login', function(req, res) {
var data = "";
var flag_isthere = 0,
wrongpass = 0;
console.log('login-done');
req.setEncoding('UTF-8')
req.on('data', function(chunk) {
data += chunk;
});
req.on('end', function() {
MongoClient.connect("mongodb://localhost:27017/userdetails", {
useNewUrlParser: true,
useUnifiedTopology: true
}, function(err, db) {
if (err) throw err;
var q = JSON.parse(data)
const mydb = db.db('userdetails')
var c = mydb.collection('signup').find().toArray(
function(err, array) { // *** Renamed `res` to `array
for (var i = 0; i < array.length; i++)
if ((array[i].email == q['email'])) //check if the account exists
{
flag_isthere = 1;
if ((array[i].pass != q['pass']))
wrongpass = 1;
break;
}
if (flag_isthere == 0) {
console.log(q['email'], ' is not registered')
} else {
console.log('Already exists!!!');
}
// *** Handle result here
if (flag_isthere == 1 && wrongpass == 0) {
console.log('Congratulations,username and password is correct');
res.send({ login: 'OK', error: '' }); //this statement is giving an error in node JS part
} else if (wrongpass == 1) {
console.log('password entered is wrong')
// *** res.send(/*...*/)
} else {
// Handle the issue that there was no match
// *** res.send(/*...*/)
}
}
); //var c
}) //mongoclient.connect
}) //req.on
// *** Don't try to send a response here, you don't know the answer yet
});
but, it seems like you should be able to find just the one user (via findOne? I don't do MongoDB), rather than finding all of them and then looping through the resulting array.
See also the answers to these two questions, which may help you with asynchronous code issues:
How do I return the response from an asynchronous call?
Why is my variable unaltered after I modify it inside of a function?
A couple of other notes:
I strongly recommend using booleans for flags, not numbers.
NEVER store actual passwords in your database!! Store a strong hash, and then compare hashes.
You might find async/await syntax more convenient to work with. I think recent MongoDB clients support promises (which you need for async/await).

Node Coroutines Parallel Flow Control with Generators and Promise

I am trying to mimic the control flow of the async.js library with coroutines and promises,using both co and bluebird.js but I am running into some issues. My code is as follows, although this is mostly psuedo code, because actual code would've been very long, I can add the acutal code later on if needed...
co(function*(){
var re = /^\w+([\.-]?\w+)*#\w+([\.-]?\w+)*(\.\w{2,3})+$/;
var doc = yield People.findOne({email: req.body.email}).exec();
var filePath = path.join(__dirname, '../email-template.html');
var html = yield fs.readFileAsync(filePath,'utf8');
var emailsToSend = [];
var emailStatuses = [];
var validEmails = [];
//make sure email is ok
req.body.messagesToSend.forEach(function(message){
if(message.email != null && re.test(message.email))
{
validEmails.push(message);
}else{
// mark it as failed...
emailStatuses.push({success : "FAILURE", email : message.email});
}
});
yield Promise.all( validEmails, Promise.coroutine(function * (message){
try{
var person = yield People.findOne({email: message.email }).exec();
if(person){
emailStatuses.push({status : "Already exists", email : message.email});
}else{
emailsToSend.push({ email: message.email, message: message.text });
}
}// else
}catch(err){
emailStatuses.push({status : "FAILURE", email : message.email});
}//
}));
if( emailsToSend.length === 0){
// no valid emails to process so just return
return res.status(200).json(emailStatuses);
}// if no emails to send
else{
yield Promise.all(emailsToSend, Promise.coroutine(function * (emailMessage){
try{
var newInvite = new Invite();
newInvite.email = emailMessage.email;
newInvite.message = emailMessage.message;
var invite = yield Invite.save();
// now try to send the email
var mailHTMl = html.replace( "{{EMAIL_PLACEHOLDER}}", req.body.registeredEmail);
var sendmail = new emailProvider.Email();
sendmail.setTos(emailMessage.email);
sendmail.setFrom(common.DEF_EMAIL_SENDER);
sendmail.setSubject(common.EMAIL_SUBJECT);
sendmail.setHtml(mailHTMl);
var successMail = yield emailProvider.send(sendmail);
emailStatuses.push({status : "SUCCESS", email : emailMessage.email});
}catch(err){
//additional logging here which ive removed for purposes of brevity
emailStatuses.push({status : "FAILURE", email : emailMessage.email});
}
}));
return res.status(200).json(emailStatuses);
}
}).catch(function(err){
//additional logging here which ive removed for purposes of brevity
return res.status(500)
});
The issue Im having is with the Promise.all, if i pass in an array, it only seems to process the first element, even though there is no rejection of the promise or any type of error.
This code works, if I use Promise.each, but then it is executed serially. What I want to achieve is basically have an async series with 2 async.foreach which will execute one after another and process each array item in parallel, but process each array sequentially, kind of like below:
async.series([
async.foreach
async.foreach
]);
However, I am not sure what I'm missing here in order to get it to execute in parallel, because it seems to work fine now if I use Promise.each and get serial execution for each array item.
So there are basically 2 ways to make this work, the first solution is to use the original code and just use Promise.map, which I'm not sure if it executes in parallel, but basically will not stop at the first array element.
The second is a fairly simple change of mapping the array values to coroutine functions, and then doing a Promise.all on those as shown below:
Although, I must note, this is visibly slower than using async.js. It would be helpful if anyone could explain why ?
co(function*(){
var re = /^\w+([\.-]?\w+)*#\w+([\.-]?\w+)*(\.\w{2,3})+$/;
var doc = yield People.findOne({email: req.body.email}).exec();
var filePath = path.join(__dirname, '../email-template.html');
var html = yield fs.readFileAsync(filePath,'utf8');
var emailsToSend = [];
var emailStatuses = [];
var validEmails = [];
//make sure email is ok
req.body.messagesToSend.forEach(function(message){
if(message.email != null && re.test(message.email))
{
validEmails.push(message);
}else{
// mark it as failed...
emailStatuses.push({success : "FAILURE", email : message.email});
}
});
//yield Promise.all( validEmails, Promise.coroutine(function * (message){
var firstPromises = validEmails.map(Promise.coroutine(function * (message){
try{
var person = yield People.findOne({email: message.email }).exec();
if(person){
emailStatuses.push({status : "Already exists", email : message.email});
}else{
emailsToSend.push({ email: message.email, message: message.text });
}
}// else
}catch(err){
emailStatuses.push({status : "FAILURE", email : message.email});
}//
}));
yield Promise.all(firstPromises);
if( emailsToSend.length === 0){
// no valid emails to process so just return
return res.status(200).json(emailStatuses);
}// if no emails to send
else{
//yield Promise.all(emailsToSend, Promise.coroutine(function * (emailMessage){
var secondPromises = emailsToSend.map( Promise.coroutine(function * (emailMessage){
try{
var newInvite = new Invite();
newInvite.email = emailMessage.email;
newInvite.message = emailMessage.message;
var invite = yield Invite.save();
// now try to send the email
var mailHTMl = html.replace( "{{EMAIL_PLACEHOLDER}}", req.body.registeredEmail);
var sendmail = new emailProvider.Email();
sendmail.setTos(emailMessage.email);
sendmail.setFrom(common.DEF_EMAIL_SENDER);
sendmail.setSubject(common.EMAIL_SUBJECT);
sendmail.setHtml(mailHTMl);
var successMail = yield emailProvider.send(sendmail);
emailStatuses.push({status : "SUCCESS", email : emailMessage.email});
}catch(err){
//additional logging here which ive removed for purposes of brevity
emailStatuses.push({status : "FAILURE", email : emailMessage.email});
}
}));
yield Promise.all(secondPromises);
return res.status(200).json(emailStatuses);
}
}).catch(function(err){
//additional logging here which ive removed for purposes of brevity
return res.status(500)
});

pass EJS variable to be used in client side <script> [duplicate]

I am completely lost on this; I am using NodeJS to fetch a JSON and I need to pass the variable to my page and have JavaScript use the data.
app.get('/test', function(req, res) {
res.render('testPage', {
myVar: 'My Data'
});
That is my Express code (very simple for testing purposes); now using EJS I want to gather this data which I know to render on the page is simply
<%= myVar %>
But I need to be able to gather this data in JavaScript (if possible within a .js file) but for now just to display the variable in an Alert box I have tried
In Jade it is like alert('!{myVar}') or !{JSON.stringify(myVar)}. Can I do something similar in EJS. I don't need any field like <input type=hidden> and taking the value of the field in javascript. If anyone can help be much appreciated
You could use this (client-side):
<script>
var myVar = <%- JSON.stringify(myVar) %>;
</script>
You could also get EJS to render a .js file:
app.get('/test.js', function(req, res) {
res.set('Content-Type', 'application/javascript');
res.render('testPage', { myVar : ... });
});
However, the template file (testPage) would still need to have the .html extension, otherwise EJS won't find it (unless you tell Express otherwise).
As #ksloan points out in the comments: you do have to be careful what myVar contains. If it contains user-generated content, this may leave your site open for script injection attacks.
A possible solution to prevent this from happening:
<script>
function htmlDecode(input){
var e = document.createElement('div');
e.innerHTML = input;
return e.childNodes.length === 0 ? "" : e.childNodes[0].nodeValue;
}
var myVar = JSON.parse(htmlDecode("<%= JSON.stringify(myVar) %>"));
</script>
The main difficulty here is to avoid XSS risks if myVar contains quotes, or </script> for example. To avoid this problem, I propose to use Base64 encoding after JSON.stringify. This would avoid all risks related to quotes or HTML tags since Base64 only contains "safe" characters to put in a quoted string.
The solution I propose:
EJS file:
<script>
var myVar = <%- passValue(myVar) %>
</script>
which will render into something like (for example here myVar = null):
<script>
var myVar = JSON.parse(Base64.decode("bnVsbA=="))
</script>
Server-side NodeJS:
function passValue(value) {
return 'JSON.parse(Base64.decode("' + new Buffer(JSON.stringify(value)).toString('base64') + '"))'
}
Client-side JS (this is an implementation of Base64 decoding that works with Unicode, you can use another if you prefer but be careful if it supports Unicode):
var Base64={_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(e){var t="";var n,r,i,s,o,u,a;var f=0;e=Base64._utf8_encode(e);while(f<e.length){n=e.charCodeAt(f++);r=e.charCodeAt(f++);i=e.charCodeAt(f++);s=n>>2;o=(n&3)<<4|r>>4;u=(r&15)<<2|i>>6;a=i&63;if(isNaN(r)){u=a=64}else if(isNaN(i)){a=64}t=t+this._keyStr.charAt(s)+this._keyStr.charAt(o)+this._keyStr.charAt(u)+this._keyStr.charAt(a)}return t},decode:function(e){var t="";var n,r,i;var s,o,u,a;var f=0;e=e.replace(/[^A-Za-z0-9\+\/\=]/g,"");while(f<e.length){s=this._keyStr.indexOf(e.charAt(f++));o=this._keyStr.indexOf(e.charAt(f++));u=this._keyStr.indexOf(e.charAt(f++));a=this._keyStr.indexOf(e.charAt(f++));n=s<<2|o>>4;r=(o&15)<<4|u>>2;i=(u&3)<<6|a;t=t+String.fromCharCode(n);if(u!=64){t=t+String.fromCharCode(r)}if(a!=64){t=t+String.fromCharCode(i)}}t=Base64._utf8_decode(t);return t},_utf8_encode:function(e){e=e.replace(/\r\n/g,"\n");var t="";for(var n=0;n<e.length;n++){var r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r)}else if(r>127&&r<2048){t+=String.fromCharCode(r>>6|192);t+=String.fromCharCode(r&63|128)}else{t+=String.fromCharCode(r>>12|224);t+=String.fromCharCode(r>>6&63|128);t+=String.fromCharCode(r&63|128)}}return t},_utf8_decode:function(e){var t="";var n=0;var r=c1=c2=0;while(n<e.length){r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r);n++}else if(r>191&&r<224){c2=e.charCodeAt(n+1);t+=String.fromCharCode((r&31)<<6|c2&63);n+=2}else{c2=e.charCodeAt(n+1);c3=e.charCodeAt(n+2);t+=String.fromCharCode((r&15)<<12|(c2&63)<<6|c3&63);n+=3}}return t}}
if you have more complex objects like an array, you can do this :
<% if (myVar) { %>
<script>
myVar = JSON.parse('<%- JSON.stringify(myVar) %>');
</script>
<% } %>
otherwise, previous solutions you have seen will not work
Try this:
<script type="text/javascript">
window.addEventListener('load', function(){
alert('<%= myVar %>');
});
</script>
Heres how i made it work,
in node js pass the json like this
let j =[];
//sample json
j.push({data:"hi});
res.render('index',{json:j});
now in js function
var json = JSON.parse('<%- JSON.stringify(json) %>');
This worked well for me
Per the documentation here:
Go to the Latest Release, download ./ejs.js or ./ejs.min.js.
Include one of these on your page, and ejs.render(str).
In the accepted solution JSON.parse will fail if myVar has a property with value with unescaped double quote. So better traverseObj and escape each string property.
Here is a function that covers my case:
function traverseObj (obj, callback)
{
var result = {};
if ( !isArray(obj) && !isObject(obj) ) {
return callback(obj);
}
for ( var key in obj ) {
if ( obj.hasOwnProperty(key) ) {
var value = obj[key];
if (isMongoId(value)){
var newValue = callback(value.toString());
result[key] = newValue;
}
else if (isArray ( value) ) {
var newArr = [];
for ( var i=0; i < value.length; i++ ) {
var arrVal = traverseObj(value[i], callback);
newArr.push(arrVal);
}
result[key] = newArr;
}
else if ( isObject(value) ) {
result[key] = traverseObj(value, callback);
}
else {
var newValue = callback(value);
result[key] = newValue;
}
}
}
return result;
};
Than in ejs you simply has to:
<%
var encodeValue = function(val) {
if ( typeof val === 'string' ) {
return sanitizeXSS(val); //use some library (example npm install xss)
}
return val;
}
var encodedProduct = ejs_utils.traverseObj(product, encodeValue);
%>
and now you can transport is safely with unescaped syntax
window.product = <%-JSON.stringify(encodedProduct)%>;
I had the similar problem. i got the value
var inJavascript = JSON.parse("<%= myVar %>");

Error handler is working in every situation

Handler is working with my code but it shouldn't alert when the the value is not null. I got an alert in either situations. I don't know what went wrong .
var data = {};
var deviceId = ["asdfa23", "asdfa32"]
data[deviceId] = "asdfasdf";
try {
if(data[deviceId].value == null)
throw "this is null"
}
catch(err) {
alert(err)
}
Just replace your in your if statements :
(data[deviceId].value == null)
by :
(data[deviceId] == null)
You don't have value field, it is not an object.
You can do .some() method to check a condition over an array.
var data = {};
var deviceId = "thermoment123";
data[deviceId] = ["er213", "er243"];
for(var device in data){
try{
var bool = data[deviceId].some(function(elm){
return elm
? true
: false
});
if (!bool){
var errorSensor = "The sensor "+ deviceId + " has no data"
throw errorSensor;
}
} catch(err){
alert(err)
}
}
You assign an array to data[deviceId].
The array has two properties 0 and 1 (along with all the inherited properties like forEach and length).
value is not a property of normal arrays and you haven't added one.
you have a couple syntax errors in your code:
var data = {};
var deviceId = "thermoment123";
data[deviceId] = ["er213", "er243"];
for (var device in data) {
try {
if (data[deviceId] == null) { //removed the .value
var errorSensor = "The sensor " + data[deviceId] + " has no data"; //added ';'
throw errorSensor;
} //close brackets that start at from if statement
} catch (err) {
alert(err); //added ';'
}
}

JavaScript if else statements to display html label

I have a log in form and am trying to display an error message if the log is incorrect.
For example;
If (email and password match) then set validUser to true.
If validUser equals true then redirect to home page
Else redirect them back to log in and display one of 3 messages...
Messages are:
'Log in unsuccessful' if both email and password are incorrect
'Password incorrect' if just the password is wrong
'Email incorrect' if just the email is wrong
Is it possible to have a loop to do all this? I can't figure it out....
Trying something like this too:
if (validUser==false)
{
$("message").show();
}
else if ( ..........)
{
$("passwordmessage").show();
}
I also want to display a message on the page and so far using this:
document.getElementById('message').style.display = ""
Here is my code: http://jsfiddle.net/2pkn1qrv/
So, how could I use if statements to do this and how can I correctly display a html page element using javascript or jquery?
Please ask if you need any more code or require clarification.
P.s. these are my users details
var USERS = {
users: []
};
function User(type, email, password) {
this.type = type;
this.email = email;
this.password = password;
}
var A = new User("rep", "a#a.com", "a");
USERS.users.push(A);
var B = new User("rep", "b#b.com", "b");
USERS.users.push(B);
var C = new User("customer", "c#c.com", "c");
USERS.users.push(C);
var D = new User("grower", "d#d.com", "d");
USERS.users.push(D);
module.exports = USERS;
You wont be having 3 conditions in that case. you will check email availability and password match. If anyone fails, you can display the message. I couldnt test your code but this will be the logic and i assume Users.user[x].email is the list of emails from your database. If yes, sorry to say that its a bad practise.
validUser = false;
emailAvailable = false;
passwordIncorrect = false;
for (var x in USERS.users) {
if(!emailAvailable && emailLog === USERS.users[x].email){
emailAvailable = true;
} //Checks whether email is available.
if(emailAvailable && passwordLog === USERS.users[x].password){
passwordIncorrect = true;
break;
} //Checks whether the password is correct for that email.
} // end of for
if(!emailAvailable){
console.log("Email is incorrect");
}
else if(emailAvailable && !passwordIncorrect){
console.log("Password is incorrect");}
else{
validUser = true;
console.log("Valid User");
}
if(validUser){
//redirect
}
I think my way is it worth to give a try:
First: create a Javascriptobject:
function ruleToCheck(errorRule, errorMsgContainer)
{
this.errorCondition = errorRule;
this.errorMessage = errorMsgContainer;
}
after that create an array and fill it with your rules:
var rulesList = new Array();
rulesList.push(new ruleToCheck("validUser === true", "message"));
...
Then loop through the array:
var rulesListLength = rulesList.length;
var index = 0;
while (index < rulesListLength)
{
index++;
...
}
The secret of success is the powerful eval() function within the while() loop:
if (eval(rulesList[index].errorCondition))
{
$("#"+rulesList[index].errorMessage).show();
break;
//If 'break does not work, use 'index = rulesListLength'
}
Hope it was helpful or at least leaded you into the right direction.
By the way, take care of the comments on your question.

Categories