Post file and data in same request to node server - node.js

I have a form in HTML with two inputs - 1 text and 1 file.
<form method="post" action="http://localhost:3000/users">
<input type="text" name="username" />
<input type="file" name="file" />
<button type="submit">Submit</button>
</form>
Now I am posting it to a node server-
router.post('/users', function(req, res, next){
req.pipe(req.busboy);
req.busboy.on('file', function(fieldname, file, filename){
var fstream=fs.createWriteStream('./uploads/'+filename);
file.pipe(fstream);
fstream.on('close', function(){
var user = User({
username: req.body.username,
});
user.save(function(err){
if(err)
res.json({error: err});
else
res.redirect('/');
});
});
});
});
But I am only able to get either username or file (when I use enctype="multipart/form-data" in HTML form.) at a time.
Is there any way to save both in a single request. If yes then how ?
Any help is appreciated.
Thanks.

You're only listening for file fields. If you want to be notified about non-file fields, then you need to also add a 'field' event listener:
req.busboy.on('field', function(key, val, keyTrunc, valTrunc) {
console.log(key, val);
});

Related

hashing password using brcrpt in "pre"

i am trying to store a hash of the password entered in a form using bcrypt in mongodb
this is the form
<form action="/register" method="POST">
<label for="firstname">Firstname</label>
<input type="text" name="firstname" id="fname" ></p><br/>
<label for="lastname">Lastname</label>
<input type="text" name="lastname" ></p><br/>
<label for="email">Email</label>
<input type="email" name="email" ></p><br/>
<label for="">Password</label>
<input type="password" name="password" ></p><br/>
<input type="submit" value="submit">
this is my mongoose schema
const userschema = new mongoose.Schema({ // define a schema
fname:{type:String,trim:true},
lname:{type:String,trim:true},
email:{type:String,lowercase:true,trim:true},
pass:{type:String}
});
and this is my pre function that is to be performed before save is called in my handler
userschema.pre('save',async function(next){
const user=this;
console.log(user); //in this log the user object this is containing plaintext value of password
await bcrypt.hash(user.pass, 8, function(err, hash) {
if(err){throw new Error(err);}
else{
user.pass=hash;
console.log(user); //and in this log the user object is containing hashed value as expected
}
})
next()}
);
and this is my handler for saving the user in the database
app.post("/register",function(req,res){
const errors = validationResult(req);
if (!errors.isEmpty()) {
console.log(errors.array());
return res.status(400).render("register",{ errors: errors.array() });
}
console.log(req.body); //out of context question but for some reason only firstname and email are visible in req.body object can anybody body explain
const usave=new user({
fname:req.body.firstname,
lname:req.body.lastname,
email:req.body.email,
pass:req.body.password
})
usave.save((err,doc)=>{
if(err){res.send(err);}
else{
res.send("success");}
});
});
when the route is handled the user is being saved succesfully but the password stored in the database is not being hashed.
I did make user.pass=hash in the schema.pre('save') function but its not being stored in the database as hash just being stored as plain text
can anybody tell me what is wrong with this code?how do i save the hashpassword to database?
userschema.pre('save', async function(next) {
var user = this;
await bcrypt.hash(user.pass, 8, function(err, hash) {
if (err) {
return next(err);
}
user.pass = hash;
next();
})
});
The above code will accomplish your goal of always hashing the password when a document is saved to the DB, passwords are not hashed until the document is saved.

Nodejs Passport authentication & local strategy not work through API Call

This is solved. Actually, the problem is with postman not on Passport code
I have a login system which is implemented through Nodejs Passport. For Login I use Handlebars for creating the UI and send the form data from frontend to backend.
These is my login Handlebars File
<form id="userloginform" method="post" action="/user/login">
<div class="form-group">
<label>Username</label>
<input type="text" name="username" class="form-control" placeholder="Username or Email">
</div>
<div class="form-group">
<label>Password</label>
<input type="password" name="password" class="form-control" placeholder="Password">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
and on User.js file I have a code of authentication i.e like this
//Login Handler
passport.use('local-user', new LocalStrategy(
function(username, password, done) {
User.getUserByUsername(username, function(err, user){
if(err) {
console.log('error')
logger.log('error', 'Error Generates on User.getUserByUsername Query on users.js file');
throw err;
}
if(!user){
return done(null, false, {message: 'Unknown User'});
}
User.comparePassword(password, user.password, function(err, isMatch){
if(err) {
logger.log('error', 'Error Generates on User.comparePassword Query on users.js file');
throw err;
}
if(isMatch){
return done(null, user);
}else{
return done(null, false, {message: 'Invalid Credential, please check carefully...!'})
}
});
});
}
));
//Login Authentication
router.post('/login',
passport.authenticate('local-user', {
failureRedirect: '/user/login',
badRequestMessage: 'Field cannot be blank.!!', //missing credentials
failureFlash: true
}),
function(req, res) {
console.log('hello');
req.flash('success_msg', 'Welcome ' + req.user.name);
req.flash('custom_msg', token);
//res.redirect('/success?username='+req.user.username);
res.redirect('/user/dashboard');
});
All these things are working pefectly.
Now when I call it through postman and pass two parameters i.e username and password then it does nothing. Simply failure redirect.
I have done this through proper nodejs with form submitted pattern. Now I want to be done through API from different Server.
Anyone have any idea then let me know. Any help is really appreciated.

bcrypt.compareSync is always returning false

I verified that in my db I am saving the username and hash of the password. I am able to retrieve the name from the db, however when I check the password it always returns false. Not sure what is wrong.
Here is my HTML
<div ng-controller="userController">
<div class=user>
<form name="login_form">
<h2 class>Login</h2>
<h3 class = "login_page">UserName</h3>
<input ng-model="user" type="text" ng-minlength="1" required>
<h3 class = "login_page">Password</h3>
<input ng-model="password" type="password" name="password" ng-minlength="4" required>
<input type="submit" value="Login" ng-click="login()" >
<div ng-if ="login_form.$submitted" ng-messages="login_form.password.$error" style="color:maroon" role="alert">
<div ng-message="minlength">Your field is too short</div>
</div>
<p ng-if="error">Username or login is incorrect</p>
</form>
</div>
<div class=user>
<form name = "register_form">
<h2 class>Register</h2>
<h3 class = "login_page">UserName</h3>
<input ng-model="reg.name" type="text" required>
<h3 class = "login_page">Password</h3>
<input ng-model="reg.password" type="password">
<input type="submit" value="Register" ng-click="register()" required >
<div ng-if ="login_form.$submitted" ng-messages="login_form.password.$error" style="color:maroon" role="alert">
<div ng-message="minlength">Your field is too short</div>
</div>
<p ng-if="duplicate">That user name is taken, please choose another</p>
<p ng-if="correct">Registration Succesfull</p>
</form>
</div>
</div>
Here is my controller on the server side
var mongoose = require('mongoose'),
Todo = mongoose.model('Todo');
Login = mongoose.model('Login');
var bcrypt = require('bcrypt');
var name = ""
module.exports = (function(){
return {
save_name:function(req, res){
req.session.user = req.body.user
Login.findOne({name: req.body.user},
function(err, user) {
if(user){
console.log(user.password);
console.log( bcrypt.compareSync(req.body.password, user.password));
res.json({'error': false});
}else {
res.json({'error': true});
}
})
}, //end of save name method
register:function(req, res){
bcrypt.hashSync(req.body.password, bcrypt.genSaltSync(8));
login = new Login({
name:req.body.user,
password: bcrypt.genSaltSync(8)
})
login.save(function(err){
if(err){
res.json({'error': true});
} else {
res.json({'sucess': true})
}
})
} // end of register user function
}
})();
You're saving a generated salt as the password instead of the actual hash itself. Also, explicitly calling genSalt*() is unnecessary. Lastly, you really should use the async functions instead, to avoid unnecessarily blocking the event loop. So with all of this in mind, you may end up with something like:
module.exports = {
save_name: function(req, res) {
req.session.user = req.body.user;
Login.findOne({ name: req.body.user },
function(err, user) {
if (err)
return res.json({ error: true });
bcrypt.compare(req.body.password,
user.password,
function(err, valid) {
res.json({ error: !!(err || !valid) });
});
});
}, // end of save name method
register: function(req, res) {
bcrypt.hash(req.body.password, 8, function(err, hash) {
if (err)
return res.json({ error: true });
login = new Login({
name: req.body.user,
password: hash
})
login.save(function(err) {
res.json({ error: !!err });
})
});
} // end of register user function
};
Despite other answers, if it is still not resolving your issue. Try by applying the toString() when passing the password upon login like this.
req.body.password.toString();
The immediate cause of your bug is in register you should be using bcrypt.hashSync(myPlaintextPassword, saltRounds) instead of genSaltSync. Fixing that should make things "work".
However, you need to recode all this to use the async bcrypt APIs or your application will respond very poorly under load (like crippled and unusable, not just "slow"). General rule: no sync calls in a node.js server.

Trying to add a business in node express framework

I'm trying to add a business in Node Express Framework. My issue is that when I fill out the form to add the business, nothing adds to the page. Been trying to figure out this error for some time now.
My business.js code:
var express = require('express');
var router = express.Router();
var mongoose = require('mongoose');
var Business = require('../models/business');
var passport = require('passport');
// set up the GET handler for the main movies page
router.get('/', function(req, res, next) {
// use the Article model to retrieve all movies
Business.find(function (err, business) {
// if we have an error
if (err) {
console.log(err);
res.end(err);
}
else {
// we got data back
// show the view and pass the data to it
res.render('movies/index', {
title: 'Business',
business: business
});
}
});
});
// GET handler for add to display a blank form
router.get('/add', function(req, res, next) {
// new
if (req.isAuthenticated()) {
res.render('movies/add', {
title: 'Add a New Business'
});
}
else {
res.redirect('/auth/login');
}
});
// POST handler for add to process the form
router.post('/add', function(req, res, next) {
// save a new article using our Article model and mongoose
Business.create( {
name: req.body.name,
city: req.body.city,
province: req.body.province,
postal: req.body.postal,
street: req.body.street
}
);
// redirect to main business page
res.redirect('/business');
});
// GET handler for edit to show the populated form
router.get('/:id', function(req, res, next) {
// create an id variable to store the id from the url
var id = req.params.id;
// look up the selected article
Business.findById(id, function(err, business) {
if (err) {
console.log(err);
res.end(err);
}
else {
// show the edit view
res.render('movies/edit', {
title: 'Business Details',
business: business
});
}
});
});
// POST handler for edit to update the article
router.post('/:id', function(req, res, next) {
// create an id variable to store the id from the url
var id = req.params.id;
// fill the article object
var business = new Business( {
_id: id,
title: req.body.title,
content: req.body.content,
date: req.body.date,
rating: req.body.rating,
actor: req.body.actor
});
// use mongoose and our Article model to update
Business.update( { _id: id }, business, function(err) {
if (err) {
console.log(err)
res.end(err);
}
else {
res.redirect('/business');
}
});
});
//get handler for delete using the article id
router.get('/delete/:id', function(req, res, next){
//grab the id parameter from the url
var id = req.params.id;
Business.remove({ _id: id }, function(err) {
if(err) {
console.log(err);
res.end(err);
}
else {
// show updated business page with redirect
res.redirect('/business');
}
});
});
////auth check
//function isLoggedIn(req, res, next) {
// //is the user authenticated>
// if (req.isAuthenticated()) {
// return next();
// }
// else {
// res.redirect('/auth/login');
// }
//}
// make public
module.exports = router;
My add.ejs code:
<%- include ../partials/header.ejs %>
<main>
<form method="post" action="add">
<fieldset>
<label for="name">Name:*</label>
<input type="text" name="name" required />
</fieldset>
<fieldset>
<label for="city">City:*</label>
<input type="text" name="city" required>
</fieldset>
<fieldset>
<p>
<label>Province:*</label>
<select id="province" required>
<option value="--">--</option>
<option value = "ontario">ON</option>
<option value = "quebec">QC</option>
<option value = "british columbia">BC</option>
<option value = "alberta">AL</option>
<option value="nova scotia">NS</option>
<option value="manitoba">MB</option>
<option value="newfoundland">NL</option>
<option value="pei">PEI</option>
</select>
</p>
</fieldset>
<fieldset>
<label for="postal">Postal Code:*</label>
<input type="text" name="postal" required>
</fieldset>
<fieldset>
<label for="street">Street Name:*</label>
<input type="text" name="street" required>
</fieldset>
<button class="btn btn-primary" type="submit">Save</button>
</form>
</main>
</body>
</html>
Thanks so much in advance!

passport.js authenticate popup window using sails.js

i need a help in passport.js authentication.
passort.js authentiction working fine.
but i dont know how can i create authentication login in popup window.
all the authentication process functions in backend.
please help me.
'linkedin': function(req, res) {
passport.authenticate('linkedin', {failureRedirect: '/login', scope: ['r_basicprofile', 'r_emailaddress']},
function(err, user) {
req.logIn(user, function(err) {
if (err) {
// console.log(err);
res.view('500');
return;
}
req.session.user = user;
return res.redirect('/user');
});
})(req, res);
},
'facebook': function(req, res) {
passport.authenticate('facebook', {failureRedirect: '/login', scope: ['email','publish_stream'],display:'popup' },
function(err, user) {
req.logIn(user, function(err) {
if (err) {
throw err;
res.view('500');
return;
}
req.session.user = user;
if (p) {
//write the post project function
}
return res.redirect('/user');
});
})(req, res);
},
this is my login page
<form action ="/auth/linkedin" method = "POST" class="columns small-12 iconized" >
<input type="hidden" value="test messge" name="title">
<button type="submit" class="icon-linkedin">Linkedin</button>
</form>
please help how can i resize the window .
One solution is jquery.lightbox_me.js found here http://www.freshdesignweb.com/demo/index.php?p=1379320109
Just follow the steps:
1) download the source code, and copy the .js file to assets/js, and copy the .css file to assets/style
2) change your html code to
<button id="loginBtn" class="btn btn-success btn-med">Login</button>
<form id="loginForm" action ="/auth/linkedin" method = "POST" class="columns small-12 iconized" display: none; >
<input type="text" value="test messge" name="title">
<button type="submit" class="icon-linkedin">Linkedin</button>
</form>
<script>
$('#loginBtn').click(function(e) {
$('#loginForm').lightbox_me({
centered: true,
onLoad: function() {
$('#loginForm').find('input:first').focus()
}
});
e.preventDefault();
});
</script>
3) This should do the trick. However eventually it will best if you keep your js scripts out of the html/ejs files, so things are more tidy.
Since Sails comes with ejs-locals, I would put the content within the tags in a separate file and make a call to <% block ... %> instead. Check this page for more info:
Sails.js - How to inject a js file to a specific route?

Resources