auto confirm users Cognito + Node JS - node.js

I trying to auto confirm my users in cognito + node Js app.
I tried this code as a Util, and here inside the function; and cant make it work
I try to go to aws documentation but the code is ambiguous and doesn't explain to much.
here is my code:
userPool.signUp(req.body.email, req.body.password, attributeList,
null, function (err, result) {
event = {
request: {
"userAttributes": {
"email": req.body.email
},
"validationData": {
"Name": "email",
"Value": req.body.email
}
},
response: {
autoVerifyEmail: true
}
}
// Confirm the user
// Set the email as verified if it is in the request
if (event.request.userAttributes.hasOwnProperty("email")) {
event.response.autoVerifyEmail = 'true';
}
// Return to Amazon Cognito
callback(null, event);
if (err) {
console.log("Error aws: ", err.message);
// return;
}
cognitoUser = result.user;
console.log('user name is ' + cognitoUser.getUsername());
next();
// return;
});
}
can anyone help me to say, what Im doing wrong?
thanks

in the signup callback you should call AdminConfirmSignUp. the syntax is given below.
https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminConfirmSignUp.html
userPool.signUp(req.body.email, req.body.password, attributeList,
null, function (err, result) {
event = {
request: {
"userAttributes": {
"email": req.body.email
},
"validationData": {
"Name": "email",
"Value": req.body.email
}
},
response: {
autoVerifyEmail: true
}
}
// Confirm the user
var confirmParams = {
UserPoolId: 'provide your user pool id', /* required */
Username: req.body.email /* required */
};
cognitoidentityserviceprovider.adminConfirmSignUp(confirmParams, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
// Set the email as verified if it is in the request
if (event.request.userAttributes.hasOwnProperty("email")) {
event.response.autoVerifyEmail = 'true';
}
// Return to Amazon Cognito
callback(null, event);
if (err) {
console.log("Error aws: ", err.message);
// return;
}
cognitoUser = result.user;
console.log('user name is ' + cognitoUser.getUsername());
next();
// return;
});
});
}

Related

How to correctly send post request

I'm setting up a web app in Angular with a restAPI in Nodejs but I can't correctly set my post request for authenticate user
I've set up my api and I can correctly test it with curl but in the client side (angular) it can't pass the condition that verify that the field required are presents
function in the API:
exports.authenticate = function(req, res) {
var new_user = new User(req.body);
if (!new_user.login || !new_user.pwd) {
res.status(400).send({
error: true,
message: 'Please provide all informations!'
});
} else {
User.authenticate(new_user, function(err, user) {
console.log('controller');
if (err) {
res.status(500).send(err);
} else {
console.log(user[0].id);
var token = jwt.sign({
id: user[0].id
}, config.secret, {
expiresIn: 3600
});
res.status(200).send({
user: user,
auth: true,
token: token
});
}
});
}
}
User.authenticate call my sql query:
sql.query("SELECT * FROM user WHERE login = ?", [user.login], function(err, res) {
if (err) {
return res.status(500).send('Error on the server ', err);
//console.log("error select: ", err);
} else {
if (!res) {
return res.status(404).send('No user found');
} else {
//sql.query("UPDATE user SET pwd = ? WHERE id = ?", [crypto.createHash('sha256').update(user.
sql.query("SELECT * FROM user WHERE pwd = ?", [crypto.createHash('sha256').update(user.pwd + r
if (err) {
console.log("error: ", err);
result(null, err);
} else {
result(null, res2);
}
});
}
}
});
Angular side (my service function):
login(loguser: User) {
return this.http.post<any>(`${environment.apiUrl}/authenticate`,
{ loguser }, { headers: new HttpHeaders().set('Content-Type', 'application/json')})
.pipe(map(user => {
// store user details and jwt token in local storage to keep user logged in between p
localStorage.setItem('currentUser', JSON.stringify(user));
this.currentUserSubject.next(user);
return user;
}));
}
login component:
onSubmit() {
this.submitted = true;
// stop here if form is invalid
if (this.loginForm.invalid) {
return;
}
this.loading = true;
this.user.login = this.f.username.value;
this.user.pwd = this.f.password.value;
console.log(this.user);
this.authenticationService.login(this.user)
.pipe(first())
.subscribe(
data => {
this.router.navigate([this.returnUrl]);
},
error => {
this.error = error;
this.loading = false;
});
}
console.log(this.user) output : {login: "cl", pwd: "cl"}
my post request is blocked in this part of my api:
if (!new_user.login || !new_user.pwd){
res.status(400).send({ error: true, message: 'Please provide all informations!' });
Because this is the answer I get when I submit the form.
I can get right answer when I test it like that:
curl -v -X POST --data '{"login":"cl","pwd":"cl"}' --header "Content-Type: application/json" https://#api:8443/autenticate
I want to get the good answer.
The problem is in your Angular code:
login(loguser: User) {
return this.http.post<any>(`${environment.apiUrl}/authenticate`,
{ loguser },
{
headers: new HttpHeaders().set('Content-Type', 'application/json')
})
.pipe(map(user => {
// store user details and jwt token in local storage to keep user logged in between p
localStorage.setItem('currentUser', JSON.stringify(user));
this.currentUserSubject.next(user);
return user;
}));
}
This piece of code:
{ loguser }
uses the "shortcut property name" syntax introduced in TypeScript and ECMAScript 2015 to create an object with a single property named loguser which has the value of the loguser variable. It is equivalent of writing:
{ loguser: loguser }
Instead, you can just pass the variable itself in your code:
login(loguser: User) {
return this.http.post<any>(`${environment.apiUrl}/authenticate`,
loguser, // Just the object itself
{
headers: new HttpHeaders().set('Content-Type', 'application/json')
})
.pipe(map(user => {
// store user details and jwt token in local storage to keep user logged in between p
localStorage.setItem('currentUser', JSON.stringify(user));
this.currentUserSubject.next(user);
return user;
}));
}
That will pass the object, with the login and pwd properties intact.

Send variables to layout

I'm learning how to build web applications using Node.js and express, so I'm really noob yet.
So, I have some questions here. I'm building a landing page, and all the informations that I'm getting from my Database (in mysql) will appear in a single page.
I'm sending values from my database, to my layout, built in Jade.
And I created multiple functions to get specific data, here an example:
function getUser(username, userId, callback) {
connection.query('SELECT * FROM users WHERE user_id = ?', userId, function(err, result) {
if (err)
callback(err, null);
else
var callBackString = {};
callBackString.value1 = result[0].user_email;
callBackString.value2 = result[0].user_name;
callback(null, callBackString);
});
}
When the user tries to login I check if the user exists to change the layout and send to the layout some important values:
router.post('/login', function(req, res) {
connection.query('SELECT user_id FROM users WHERE user_email = ? AND user_password = ?', [req.body.login, req.body.password], function(err, results) {
if (err) throw err;
if (results[0]) {
userId = results[0].user_id;
getUser("username", userId, function(err, data) {
if (err) {
console.log("ERROR : ", err);
} else {
res.render('logged_in', {
email: data.value1,
username: data.value2,
});
res.end();
}
});
} else {
res.render('index', {
validation: "failed"
});
}
});
});
I'm only calling one function here (getUser()), and when I call this function, the layout changes, and I send some values.
But now I would like to create a new function called getPosts(), to get informations from a different table, and send it to the layout too, like I did when i called the function getUser()
I tried to do something like this but I had no success, when I call the variables outside the scope I keep getting "undefined".
router.post('/login', function(req, res) {
connection.query('SELECT user_id FROM users WHERE user_email = ? AND user_password = ?', [req.body.login, req.body.password], function(err, results) {
if (err) throw err;
if (results[0]) {
userId = results[0].user_id;
getUser("username", userId, function(err, data) {
if (err) {
console.log("ERROR : ", err);
} else {
email = data.value1;
username = data.value2;
}
});
getPosts("posts", 1, function(err, data) {
if (err) {
console.log("ERROR : ", err);
} else {
postName = data.value1;
postText = data.value2;
}
});
res.render('logged_in', {
email: email,
username: username,
pstname: postName,
psttxt: postText
});
res.end();
} else {
res.render('index', {
validation: "failed"
});
}
});
});
What do I need to change on my code? Thank you.
You should read about asynchronization in node.js so if you change your code as bellow it may work:
router.post('/login', function(req, res) {
connection.query('SELECT user_id FROM users WHERE user_email = ? AND user_password = ?', [req.body.login, req.body.password], function(err, results) {
if (err) throw err;
if (results[0]) {
userId = results[0].user_id;
getUser("username", userId, function(err, data) {
if (err) {
console.log("ERROR : ", err);
} else {
email = data.value1;
username = data.value2;
getPosts("posts", 1, function(err, data) {
if (err) {
console.log("ERROR : ", err);
} else {
postName = data.value1;
postText = data.value2;
res.render('logged_in', {
email: email,
username: username,
pstname: postName,
psttxt: postText
}
});
}
});
} else {
res.render('index', {
validation: "failed"
});
}
});
});

Mongoose - use findOne multiple times at once

Disclaimer: I am a newb web dev.
I am creating a registration page. There are 5 input fields, with 3 of them (username, password, and email) requiring that they pass various forms of validation. Here is the code:
router.post('/register', function (req, res, next) {
user.username = req.body.username;
user.profile.firstName = req.body.firstName;
user.profile.lastName = req.body.lastName;
user.password = req.body.password;
user.email = req.body.email;
User.findOne({email: req.body.email}, function(err, existingEmail) {
if(existingEmail) {
console.log(req.body.email + " is already in use")
} else {
User.findOne({username: req.body.username}, function(err, existingUsername) {
if(existingUsername) {
console.log(req.body.username + " is already in use");
} else {
user.validate({password: req.body.password}, function(err) {
if (err) {
console.log(String(err));
} else {
user.save(function(err, user) {
if (err) {
return next(err);
} else {
return res.redirect('/')
}
})
}
});
}
});
}
});
});
Basically it first checks to see if it is a duplicate e-mail; if it is a duplicate e-mail, it says so in the console.log. If it isn't a duplicate e-mail, it then checks the username.... and then goes onto the password.
The issue is that it does this all one at a time; if the user inputs an incorrect email and username, it will only say that the email is incorrect (it won't say that both the email and username are incorrect).
How can I get this to validate all 3 forms at the same time?
You can use async to run them in parallel and it will also make your code cleaner and take care of that callback hell:
var async = require('async');
async.parallel([
function validateEmail(callback) {
User.findOne({email: req.body.email}, function(err, existingEmail) {
if(existingEmail) {
callback('Email already exists');
} else {
callback();
}
}
},
function validateUsername(callback) {
User.findOne({username: req.body.username}, function(err, existingUsername) {
if(existingUsername) {
callback('Username already exists');
} else {
callback();
}
}
},
function validatePassword() {
user.validate({password: req.body.password}, function(err) {
if(err) {
callback(err);
} else {
callback();
}
}
}
], function(err) {
if(err) {
console.error(err);
return next(err);
} else {
user.save(function(err, user) {
if (err) {
return next(err);
} else {
return res.redirect('/');
}
});
}
}
);
This way, all the validation methods inside the array will be run in parallel and when all of them are complete the user will be saved.
If you use else statements, you choose to make checks individually (one at a time) by design.
To achieve an 'all at once' behaviour, I would not use else statements (where possible, i.e. errors ar not fatal for next checks), but would do all tests in the same block, and would fill an object like this:
errors: {
existingEmail: false,
existingUserName: false,
invalidUserName: false,
wrongPassword: false,
...
};
And then I'd use it in the form to show user all errors together...
Something like this:
var errors = {};
if (existingEmail) {
console.log(req.body.email + " is already in use");
errors.existingEmail: true;
}
User.findOne({username: req.body.username}, function(err, existingUsername) {
if (existingUsername) {
console.log(req.body.username + " is already in use");
errors.existingUsername: true;
} else {
user.validate({password: req.body.password}, function(err) {
if (err) {
console.log(String(err));
errors.invalidUsername = true;
} else {
user.save(function(err, user) {
if (err) {
return next(err);
} else {
return res.redirect('/')
}
})
}
});
}
});

Value not being updated in DB, node.js and mongoose

I am trying to update the value of my model and it does not work.
The weird thing is that I am printing out the result and it looks different than what I see in my database by using Robomongo.
Any thoughts why this happens?
Here is my code:
exports.create = function(req, res) {
var productId = req.query.product;
if (productId) {
Request.createWizard(req.user, { productId: productId }, function(err, request) {
Product.findById(productId, function(err, product) {
if (err) {
return console.log('oh no! error', err);
} else {
if (product.price =! 0 )
request.status = 'ready';
console.log(request);
(Here I see in the terminal: status = ready)
}
});
req.flash('success', { msg: 'Your request has been successfully created.' });
res.redirect('/discover');
});
} else {
var pages = require('../../schemas/wizard/request')();
res.render('requests/form', {
title: 'Make a Request',
pages: pages,
saveState: false
});
}
};
When I am checking the database status is still on pending.
You're changing the status property, but you're not saving the document back to the database after doing so:
Request.createWizard(req.user, { productId: productId }, function(err, request) {
Product.findById(productId, function(err, product) {
if (err) {
return console.log('oh no! error', err);
} else {
if (product.price !== 0) {
request.status = 'ready';
request.save(function(err) { // <-- save it back to the database
if (err) {
console.log('oh no! error', err);
} else {
console.log(request);
}
});
}
}
});
req.flash('success', { msg: 'Your request has been successfully created.' });
res.redirect('/discover');
});

Q-promises and error handling

I am trying to understand Q Promises and how to handle two different errors thrown from two different then blocks.
Here is the function I would like to "Promisfy":
router.post('/user', function(req, res) {
var user = new User(req.body);
User.findOne({ email: req.body.email }, function(error, foundUser) {
if(foundUser) {
res.send("Error: User with email " + foundUser.email + " already exists.", 409);
} else {
User.create(user, function(err, createdUser) {
if (err) {
res.send(err, 400);
} else {
res.json({ id: createdUser.id }, 201);
}
});
}
});
});
It takes some User details, and tries to create a new User if one doesn't exist already with the same email. If one does, send a 409. I also handle the normal mongoose error with a 400.
I've tried using mongoose-q to convert it over, and I end up with this:
router.post('/user', function(req, res) {
var user = new User(req.body);
User.findOneQ({email : req.body.email})
.then(function(existingUser) {
if (existingUser) {
res.send("Error: User with email " + existingUser.email + " already exists.", 409);
}
return User.create(user);
})
.then(function(createdUser) {
res.json({ id: createdUser.id }, 201);
})
.fail(function(err) {
res.send(err, 400)
})
});
Is this correct? Is there anyway to push that existing user check into a fail block? I.e. throw an Error, and then catch it and deal with it?
Something like this perhaps:
router.post('/user', function(req, res) {
var user = new User(req.body);
User.findOneQ({email : req.body.email})
.then(function(existingUser) {
if (existingUser) {
throw new Error("Error: User with email " + existingUser.email + " already exists.");
}
return User.create(user);
})
.then(function(createdUser) {
res.json({ id: createdUser.id }, 201);
})
.fail(function(duplicateEmailError) {
res.send(duplicateEmailError.message)
})
.fail(function(mongoError) {
res.send(mongoError, 400)
})
});
I'm not experienced enough with Q. However, I can answer with bluebird.
bluebird supports typed catches. Which means you can create new Error subclasses, throw them, and handle them accordingly.
I've used newerror in my example to simplify the creation of Error subclasses.
var newerror = require('newerror');
var DuplicateEmailError = newerror('DuplicateEmailError');
router.post('/user', function(req, res) {
var user = new User(req.body);
User.findOneAsync({ email: req.body.email }).then(function(existingUser) {
if (existingUser) {
throw new DuplicateEmailError('Error: User with email ' + existingUser.email + ' already exists.');
}
return User.createAsync(user);
}).then(function(createdUser) {
res.json({ id: createdUser.id }, 201);
}).catch(DuplicateEmailError, function(err) {
res.send(err.message, 409);
}).catch(function(err) {
res.send(err.message, 500);
});
});

Resources