MONGODB findOne() needs a variable - javascript

My function is set to find email brought from /login POST method, but I am failing to declare the variable properly, what is the variable to be inserted into the findOne form on app.get('/data')?
I have:
app.post('/login', function (req, res) {
//console.log(req.body);
const uri = "mongodb+srv://<PRIVATE INFO>.eapnyil.mongodb.net/?retryWrites=true&w=majority";
const client = new MongoClient(uri, { useNewUrlParser: true, useUnifiedTopology: true, serverApi: ServerApiVersion.v1 });
const users = client.db("data").collection("users");
users.findOne({email:req.body.email},function(err,data){
if(data){
if(data.password==req.body.password){
//console.log("Logged In.");
console.log('Email in DB is: ' + data.email);
console.log('Email in form is: ' + req.body.email);
//res.send({"Success":"Success!"});
res.redirect('/data');
}else{
res.send({"Failed with":"Wrong password!"});
}
}else{
res.send({"Try again":"Email not registered!"});
}
});
});
app.get('/data', (req, res) => {
const users = client.db("data").collection("users");
users.findOne({unique_id:req.session.id})((err, result) => {
if (err) return console.log(err)
// renders index.ejs
res.render('pages/data.ejs', {users: result})
})
});
and on the login.ejs file the following:
<p>Login</p>
</div>
<div class="form-group">
<form id="form" method="POST" action="/login">
<input type="text" name="email" placeholder="E-mail" required="" class="form-control"><br/>
<input type="password" name="password" placeholder="Password" required="" class="form-control"><br/>
<input type="submit" value="Login" class="btn btn-success">
</form>
</div>

Not sure why you are redirecting to the /data method when you already have the user to pass to the view.
Try to redirect in /login directly:
app.post('/login', function (req, res) {
//console.log(req.body);
const uri =
'mongodb+srv://<PRIVATE INFO>.eapnyil.mongodb.net/?retryWrites=true&w=majority';
const client = new MongoClient(uri, {
useNewUrlParser: true,
useUnifiedTopology: true,
serverApi: ServerApiVersion.v1,
});
const users = client.db('data').collection('users');
users.findOne({ email: req.body.email }, function (err, data) {
if (data) {
if (data.password === req.body.password) {
res.render('pages/data.ejs', {users: data})
} else {
res.send({ 'Failed with': 'Wrong password!' });
}
} else {
res.send({ 'Try again': 'Email not registered!' });
}
});
});
Also, I suggest you hash the password that you store in the database using libraries like bcrypt.
Storing credentials in plain text is a bad security practice.

app.get('/data', (req, res) => {
const users = client.db("data").collection("users");
users.findOne({unique_id:req.session.id},((err, result) => {
if (err) return console.log(err)
// renders index.ejs
res.render('pages/data.ejs', {users: result})
}))
});
there is a syntax error after {unique_id:req.session.id}, replace ')' for ',' and close ')' correctly

Related

Why a variable is not defined in EJS

I'm developing an application with Node.js and EJS but there is an error. It says "msg_type is not defined". When I'm using handlebars, there is no problem. What is my mistake. Actually, when url goes to /auth/login , the message is displaying but it's not displaying in /login routing.
my users.js file (controllers)
exports.login = async (req, res,next) => {
try {
const { email, password } = req.body;
if (!email || !password) {
return res.status(400).render("login", {
msg: "Kullanıcı Adınız veya Parolanız Hatalı",
msg_type: "error",
},
next()
);
}
await login_db.query(
"select * from users where email=?",
[email],
async (error, result) => {
console.log(result);
if (result.length <= 0) {
return res.status(401).render("login", {
msg: "E-mailiniz veya Parolanız Hatalı",
msg_type: "error",
});
} else {
if (!(await bcrypt.compare(password, result[0].PASS))) {
return res.status(401).render("login", {
msg: "E-mailiniz veya Parolanız Hatalı",
msg_type: "error",
});
} else {
const id = result[0].ID;
const token = jwt.sign({ id: id }, process.env.JWT_SECRET, {
expiresIn: process.env.JWT_EXPIRES_IN,
});
console.log("The Token is " + token);
const cookieOptions = {
expires: new Date(
Date.now() +
process.env.JWT_COOKIE_EXPIRES * 24 * 60 * 60 * 1000
),
httpOnly: true,
};
res.cookie("joes", token, cookieOptions);
res.status(200).redirect("/anasayfa");
}
}
}
);
} catch (error) {
console.log(error);
}
};
my auth.js file
const express = require("express");
const userController = require("../controllers/users");
const router = express.Router();
router.post("/login", userController.login);
my login.ejs file
<% if (true) { %>
<p class="<%= msg_type %>"><%= msg %> </p>
<% } %>
<form action="/auth/login" method="post">
<div class="data">
<label for="email">Email</label>
<input type="email" name="email" id="email" />
</div>
<div class="data">
<label for="password">Şifre</label>
<input type="password" name="password" id="password" />
</div>
<div class="forgot-pass">
Şifrenizi mi unuttunuz?
</div>
<div class="btn">
<button type="submit">Giriş Yap</button>
</div>
<div class="signup-link">
Kayıtlı değil misin? Şimdi Kayıt Ol!
</div>
</form>
my app.js file
app.use("/", require("./routes/pages"));
app.use("/auth", require("./routes/auth"))
;
my pages.js file
router.get(["/", "/login"], (req, res) => {
//res.send("<h1>Hello Tutor Joes Salem</h1>");
res.render("login");
});
The variable should be exported from the original file(users.js) and also should be imported in login.ejs, so you can use it without problems, this is how things work in Javascript.

Inside a MongoDB find function, I callback and use a res.redirect, I get a cannot set header error?

I'm trying to search for a user/shop account in my database (mongoDB) and then either refresh the login page but with some errors, or send them to their required page.
So far sending them to their required page works, however I get this error message from my Node console when trying to res.redirect to the /signin page.
throw err;
^
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
Here is the actual code
//Rendering Signin Page
app.get('/signin', function(req, res) {
res.render('signin', {
err: false,
})
});
//Rendering Signin Page with err
app.get('/signin/err', function(req, res) {
res.render('signin',{
err: true,
})
});
app.post('/signin', function(req, res) {
let data = req.body;
User.find({email: data.email},'_id email password', function(err, docs) {
if(err) {
console.log(err);
}
else {
//Finding the matching user
for(i = 0; i < docs.length; i++) {
if(data.password == docs[i].password) {
res.redirect('/'+docs[i]._id + '/userhome')
}
}
if(docs.length === 0) {
console.log('no user found')
res.redirect('/signin/err');
return;
}
}
})
Shop.find({email: data.email}, '_id email password', function(err,docs) {
if(err) {
console.log(err);
}
else {
//Finding the matching user
for(i = 0; i < docs.length; i++) {
if(data.password == docs[i].password) {
res.redirect('/'+docs[i]._id + '/shophome')
}
}
if(docs.length === 0) {
console.log('no shop found')
res.redirect('/signin/err')
break;
}
}
})
})
Also here is the Pug file I'm trying to render (I don't think this is the issue)
doctype html
html
head
title uShop
//Bootstrap CSS
link(rel="stylesheet", href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous")
script(src='https://code.jquery.com/jquery-3.3.1.slim.min.js', integrity='sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo', crossorigin='anonymous')
script(src='https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js', integrity='sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1', crossorigin='anonymous')
script(src='https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js', integrity='sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM', crossorigin='anonymous')
body
nav(class="navbar navbar-expand-md navbar-dark bg-dark sticky-top")
a(class="navbar-text" style="font-size:175%; color:white; padding:0px" href="/") uShop.com
h1(class="display-2 text-center position-relative" style="top: 3rem; font-size: 400%") Sign In
form(action="/signin" method="POST")
div(class="form-row position-relative" style="top:7rem")
label(class="col-lg-4 col-form-label position-relative text-right" for="inputEmail" style="font-size: 150%; top:-5px; left: -5px;") Email:
input(class="form-control col-lg-4" type="email" name="email" id="inputEmail")
//- if err == true
//- div(class="invalid-feedback") email incorrect
br
div(class="form-row position-relative" style="top:7rem")
label(class="col-lg-4 col-form-label position-relative text-right" for="inputPassword" style="font-size: 150%; top:-5px; left: -5px;") Password:
input(class="form-control col-lg-4" type="password" name="password" id="inputPassword")
div(class="form-row position-relative" style="top:8rem")
input(class="btn btn-primary btn-lg offset-lg-4 " type="submit" value="Sign In")
app.post('/signin', function (req, res) {
let data = req.body;
User.find({ email: data.email }, '_id email password', function (err, docs) {
res.redirect('/' + ...);
})
Shop.find({ email: data.email }, '_id email password', function (err, docs) {
res.redirect('/' + ...);
});
})
res.redirect cannot run twice in each request, but, from your couse, at least called twice
How about this?
app.post('/signin', function (req, res) {
let data = req.body;
User.find({ email: data.email }, '_id email password', function (err, docs) {
// res.redirect('/' + ...);
Shop.find({ email: data.email }, '_id email password', function (err, docs) {
res.redirect('/' + ...);
});
});
})
Also, ???
You need redirect to
'/' + docs[i]._id + '/shophome'
and
'/' + docs[0]._id + '/userhome'
in signin API at onece(one request)?
I think, this is impossable with http(rest api) request,
and nodejs and other language is same.
Also, I think, this is purpose of normal user.
As you want to search in either user or shop collection.
Add async/await it will make your code more readable
app.post('/signin', async function(req, res) {
....
})
You need to use findOne for both collection search and usingemail and password both in search params so no further password check needed in code
const userResult = await User.findOne({ email: data.email, password: data.password }, '_id email password');
const shopResult = await Shop.findOne({ email: data.email, password: data.password }, '_id email password');
As findOne returns object as a result if email and password matches.
You can check that if both results are empty then redirect as below
if(!userResult && !shopResult) {
return res.redirect('/signin/err');
}
if(userResult) {
return res.redirect('/'+userResult._id + '/userhome')
}
if(shopResult) {
return res.redirect('/'+shopResult._id + '/shophome')
}
Adding return on reach redirect will ensure that code execution has ended at that point.
Use try/catch to log unwanted errors.
MND link for async/await : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function

Req.body is returning the wrong kind of object

I am sending a simple register form (POST fetch) to the backend for processing. However, the request body is not being received how it should.
I expect to see request.body = {"username": "john", "password": "password"}
But I when I am console logging it I see
{ '{"username":"car","password":"car"}': '' }
Here is my fetch:
fetchRegister = (e) => { //triggered when submitting Register Info
e.preventDefault();
const registerOptions = {
method: "POST",
mode: "no-cors",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: JSON.stringify({
username: this.state.regUsername, //The inputChange function will set these to whatevr the user types
password: this.state.regPassword,
}),
}
fetch("http://localhost:5000/register", registerOptions)
.then(response => response.json())
.then(data =>
console.log(data)
)
}
And here is my endpoint:
app.use(bodyParser.urlencoded({ extended: true}))
app.use(bodyParser.json());
app.post('/register', (req, res) => {
console.log(req.body);
const inputUsername = req.body.username;
const inputPassword = req.body.password;
let newUser = new User({
userName: inputUsername,
password: inputPassword
})
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(newUser.password, salt, function(err, hash) {
if(err) {
res.send(err);
}
newUser.password = hash;
newUser.save((err) => {
if (err) {
console.log(err)
res.send(JSON.stringify({'message': 'Username is already taken'}));
}else {
res.send(JSON.stringify({'message': 'you were successful'}));
}
})
});
})
})
<div id="registerForm">
<form>
<legend>Register:</legend>
Choose a Username:<input className="reg" value={this.state.regUsername} onChange={this.inputChange("regUsername")} required></input>
Choose your Password:<input className="reg" type="password" value={this.state.regPassword} onChange={this.inputChange("regPassword")} required></input>
<button className="FORMbtn" onClick={this.fetchRegister} type="submit">Register Me</button>
</form>
</div>
I just want a standard object being sent to my backend. I have no idea whether CORS or my application type is messing it up. It works perfectly fine in postman.
It was a CORS issue. I had to install 'cors' with NPM, and bring it into Express. I could then take out 'mode': 'no-cors' and it worked.

PassportJS Local Strategy

It's my first time implementing passport strategies (using this tutorial https://scotch.io/tutorials/easy-node-authentication-setup-and-local) and I think I made a small mistake that cause a weird problem. First time login with email and password, no problem (db connected, user login successful) second time with same email and password I get rangeError: Invalid status code: 1 and crash nodemon.
I tried to find more info on this error but there really isn't any out there. I did come across someone else with similiar issue but no one answered his question since October. Anyone care to take a crack at this?
routes.js
app.post('/login', passport.authenticate('local'), function (req, res {
console.log("passport user" + req.user);
res.status(200).json({
user: req.user
});
});
app.get('/user/auth', auth.isAuthenticated, function (req, res) {
if (req.user) {
res.status(200).json({
user: req.user
});
} else {
res.sendStatus(401);
}
});
app.post("/api/user", function (req, res) {
const user = req.body;
console.log(user);
User.findOne({ 'local.email': user.email },
function (err, result) {
if (err) {
console.log(err);
handleError(err, res);
return;
}
if (result) {
res.status(500).send("Email already exists in database");
} else {
var newUser = new User();
newUser.local.password = createHash(user.password);
newUser.local.email = user.email;
newUser.local.name = user.name;
newUser.local.mobile = user.mobile;
newUser.save(function (err, result) {
res.status(201).send("User added to database");
});
}
});
});
auth.js
passport.use(new LocalStrategy({ // redefine the field names the strategy (passport-local) expects
usernameField: 'username',
passwordField: 'password',
passReqToCallback : true
}, function(req, email, password, done) {
// asynchronous
// User.findOne wont fire unless data is sent back
process.nextTick(function() {
// find a user whose email is the same as the forms email
// we are checking to see if the user trying to login already exists
User.findOne({ 'local.email' : email }, function(err, user) {
// if there are any errors, return the error
if (err)
return done(err);
// check to see if theres already a user with that email
if (user) {
return done(null, false, req.flash('signupMessage', 'That email is already taken.'));
} else {
// if there is no user with that email
// create the user
var newUser= new User();
// set the user's local credentials
newUser.local.email= email;
newUser.local.password = newUser.generateHash(password);
// save the user
newUser.save(function(err) {
if (err)
throw err;
return done(null, newUser);
});
}
});
});
}
var isAuthenticated = function(req, res, next) {
//console.log("isAuthenticated(): ", req.user);
if (req.isAuthenticated()) {
next(); //good moves to the next one
}
else {
res.sendStatus(401);
}
}
return {
isAuthenticated: isAuthenticated,
}
};
user.js
var mongoose = require('mongoose');
var bcrypt = require('bcrypt-nodejs');
// define the schema for our user model
var userSchema = mongoose.Schema({
local: {
id: String,
email: String,
password: String,
name: String,
mobile: String
},
google: {
id: String,
token: String,
email: String,
name: String
}
});
// methods ======================
// generating a hash
userSchema.methods.generateHash = function(password) {
return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
};
// checking if password is valid
userSchema.methods.validPassword = function(password) {
return bcrypt.compareSync(password, this.local.password);
};
// create the model for users and expose it to our app
module.exports = mongoose.model('User', userSchema);
html
<div class="panel panel-default">
<div class="panel-body">
<form name='loginForm' ng-submit='ctrl.login()' novalidate>
<div class="form-group">
<input class="form-control" type="text" name="username" placeholder="EMAIL" id="username" ng-model='ctrl.user.username'></div>
<div class="form-group">
<input class="form-control" type="password" name="password" placeholder="PASSWORD" id="password" ng-model='ctrl.user.password'></div>
<div class="form-group">
<input id="submit" name="submit" type="submit" class="btn btn-full btn-block" value="Log In"></div>

How to make user registration with Node.js and MongoDB (using mongoose and Express.js)

I need your help. I want to make User registration form and use Nodejs, Express.js, MongoDB(mongoose) and give me very simple example how to make user registration form with: Name, Email, Password and Mobile Number :) I've made mongoose schema and give values like that Name: req.body.name but it won't work :/ In my oppinion I made something bad.
this is my code and if you think it's not correct, please correct it. (sorry for my bad english). this is server.js
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/addressbookdb');
var express = require('express');
var app = express();
var db = mongoose.connection;
app.use(express.static(__dirname + '/../client'));
app.post("/",function(req,res){
res.end("Registration Succesfully Completed!");
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function (callback) {
console.log("connected.")
});
// Schema
var RegSchema = mongoose.Schema({
Name: String,
Email: String,
Pass: String,
Num: Number,
reg_time : {
type : Date, default: Date.now
}
}, { collection: 'AddressCol' });
// Model
var UserReg = mongoose.model('UserReg', RegSchema);
// Add in collection
var UserAdd = new UserReg({
Name: req.body.name,
Email: req.body.email,
Pass: req.body.pass,
Num: req.body.num,
});
// Save
UserAdd.save(function (err, fluffy) {
if (err) return console.error(err);
});
});
app.listen(8000, function() {
console.log("Server is running!");
});
and this is my HTML page:
<div class="form-group">
<input type="text" class="form-control" id="name" placeholder="name><br>
<input type="email" class="form-control" id="email" placeholder="Email"><br>
<input type="password" class="form-control" id="pass" placeholder="Password"><br>
<input type="number" class="form-control" id="num" placeholder="Number"><br>
<button type="submit" class="btn btn-primary" id="reg-form-btn">Registration!</button>
</div>
<script>
$(document).ready(function() {
$("#reg-form-btn").click(function() {
var name = $("#name").val();
var email = $("#email").val();
var pass = $("#pass").val();
var num = $("#num").val();
$.post("/", {
Name: name,
Email: email,
Pass: pass,
Num: num
});
});
});
</script>
Maybe you should consider Passport or another module.
But you can do something like this:
app.post('/signup', function (req, res, next) {
var user = {
Name: req.body.name,
Email: req.body.email,
Pass: req.body.pass,
Num: req.body.num
};
var UserReg = mongoose.model('UserReg', RegSchema);
UserReg.create(user, function(err, newUser) {
if(err) return next(err);
req.session.user = email;
return res.send('Logged In!');
});
});
app.post('/login', function (req, res, next) {
var email = req.body.email;
var pass = req.body.pass;
User.findOne({Email: email, Pass: pass}, function(err, user) {
if(err) return next(err);
if(!user) return res.send('Not logged in!');
req.session.user = email;
return res.send('Logged In!);
});
});
app.get('/logout', function (req, res) {
req.session.user = null;
});
Then you should have a middleware to handle authentication
function isLoggedIn (req, res, next) {
if (!(req.session && req.session.user)) {
return res.send('Not logged in!');
}
next();
}
And use it on the private routes
app.get("/api", isLoggedIn, function (req, res) {
//Something private
})
Here is a nice tutorial how to make what you want using very useful module passport. Also you will have a quick look at Jade template engine which can be useful in your further learning of creating express apps.
check this tutorial...you can ignore Angular and mongojs if you want:
http://www.phloxblog.in/single-page-application-angular-js-node-js-mongodb-mongojs-module/#.Vc20OXW1Gkq
You are missing body-parser. Try this in your server code:
const bodyParser = require('body-parser');
app.use(bodyParser);
Please refer the question How to access the request body when POSTing using Node.js and Express?

Categories

Resources