Exporting Multiple Objects Stops My HTML Requests from being processed - javascript

I have some simple javascript code in three files. There is my server.js, which has
const userRouter = require('./routes/users')
app.use("/",userRouter)
Then there is my middleware users.js with
module.exports = router
and lastly user.js with
module.exports = {
User:User,
validateLogin:validateUserLogin,
validateRegister:validateUserRegister,
}
When my user.js had just the export line module.exports = User my code worked just fine. server.js imports users.js, which imports user.js. But when exporting functions along with my User object, my requests stop working. Why? How can I fix this? I'm using Node.js with express and mongo db. All my HTML requests are in users.js.
The code to my server.js is
const express = require('express');
const bodyParser = require("body-parser");
const mongoose = require("mongoose");
//just show server is running
const app = express()
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
const PORT = 4000;
app.get("/status", async (req, res) => {
return res.status(400).send("server for GET is running");
});
app.post("/status", async (req, res) => {
return res.status(200).send({
status: "server for POST is running",
message: req.body.message
});
});
app.listen(PORT, function() {
console.log(`server running on port ${PORT}`);
});
const url = "mongodb+srv://Admin:strongpassword#cluster0.tjual.mongodb.net/ConfusedTom?retryWrites=true&w=majority"
mongoose.connect(url, {
useNewUrlParser: true,
useUnifiedTopology: true,
dbName: "ConfusedTom"
}).then(() => {
console.log("connected successfully to server, using database %s\n", mongoose.connection.$dbName);
}).catch(err => {
console.log(err);
});
const userRouter = require('./routes/users')
app.use("/",userRouter)
and here is my users.js
const mongoose = require("mongoose");
const express = require("express");
const router = express.Router();
const ObjectId = mongoose.Types.ObjectId;
const Review = require("../models/review.js")
const TVShow = require("../models/tvshows.js")
const { User, validateLogin, validateRegister} = require("../models/user.js")
router.get("/username", async (req, res) => {
console.log("reached!")
var user = await User.findOne({ username: req.body.username });
if (!user) return res.status(400).send("User doesn't exist.");
return res.status(200).send(user)
});
router.post("/register", async(req,res) => {
const { error } = validateRegister(req.body);
if (error) return res.status(400).send(error.details[0].message);
else user = await User.findOne({ username: req.body.username });
if (user) return res.status(400).send("Username already taken.");
//create new user
user = new User({
firstName: req.body.firstName,
lastName: req.body.lastName,
username: req.body.username,
password: req.body.password,
});
user.save();
return res.status(200).send("User registered successfully.");
})
router.post("/login", async (req, res) => {
console.log("reached!")
// validate the request body first
const { error } = validateLogin(req.body);
if (error) return res.status(400).send(error.details[0].message);
//find an existing user
var user = await User.findOne({ username: req.body.username });
if (!user) return res.status(400).send("Username reqired.");
if (user) {
if (user.validatePassword(req.body.password)) {
return res.header.status(200).send("User login successfully");
}
else return res.status(400).send("Password is incorrect");
} else return res.status(400).send("User doesn't exist.");
});
module.exports = router

The problem with your updated import of the stuff from user.js is you're using the wrong names for the functions. You currently have:
const UserStuff = require("../models/user.js")
const User = UserStuff.User;
const validateLogin = UserStuff.validateUserLogin;
const validateregister = UserStuff.validateUserRegister;
but the object you're exporting is:
module.exports = {
User:User,
validateLogin:validateUserLogin,
validateRegister:validateUserRegister,
}
You're using the wrong names of the functions (validateUserLogin instead of validateLogin). The names you use have to match at both ends. So:
const UserStuff = require("../models/user.js")
const User = UserStuff.User;
const validateLogin = UserStuff.validateLogin;
// ^^^^^^^^^^^^^
const validateregister = UserStuff.validateRegister;
// ^^^^^^^^^^^^^^^^
or more concisely:
const { User, validateLogin, validateRegister} = require("../models/user.js")

Related

I don't want to login if I already login in node js

Everything is going great which I shared code but the problem is that when I log in the next time when I visit the website it shows me again the login form so I don't want this process repeatedly
I used there bcrypt,jwt token and cookies for user login
This is my route where I define user register and login
router.post("/api/usersave", urlencodedParser, vUserController.createUser)
router.post("/api/userlogin", urlencodedParser, vUserController.loginUser)
This is my controller of user registration and login
const express = require("express");
const app = express();
const path = require("path")
var bodyParser = require('body-parser')
const mongoose = require("mongoose")
const hbs = require('hbs');
const router = express.Router()
const bcrypt = require("bcrypt")
const jwt = require("jsonwebtoken")
const cookieparser = require("cookie-parser")
exports.createUser=(req, res)=>{
// console.log(req.body.itemname)
const oldUser = userModel.findOne({ username: req.body.username });
if (oldUser) {
return res.status(409).send("User Already Exist. Please Login");
}
const rsUsers = new userModel(req.body)
rsUsers.save().then(() => {
console.log('User: ' + req.body.username + ' Saved')
}).catch((err)=>{
console.log('User Saved Error..' + err)
});
res.render("home", {abc: req.body})
// res.send("User Created ... ")
return true
}
exports.loginUser= async (req, res)=>{
// console.log(req.body.username)
// console.log(password)
var password = req.body.password
const findUser = await userModel.findOne({username: req.body.username})
// console.log(findUser.username)
if (!findUser){
res.send("User ID Not Found")
}
else {
bcrypt.compare(req.body.password, findUser.password, function(err, result) {
if (!result){
// console.log('User Login Failed')
res.send("User Login Failed")
}
else{
console.log('User Login Successfully')
const vToken = findUser.generateJWTToken()
res.cookie("node1", vToken)
// console.log(vToken)
res.render("home", {abc: req.body})
}
});
}
}
This is my model of user registration and login
const express = require("express");
const app = express();
const path = require("path")
var bodyParser = require('body-parser')
const mongoose = require("mongoose")
const bcrypt = require('bcrypt')
const jwt = require("jsonwebtoken")
const schema2 = new mongoose.Schema({
username: {type: String, required: true},
useremail: String,
password: String,
tokens: [{
token: String
}]
})
schema2.pre('save', async function(next){
// var saltrange = bcrypt.genSalt(10)
if(this.isModified("password")){
var saltrange = 10
this.password = bcrypt.hashSync(this.password, saltrange)
next()
}
})
schema2.methods.generateJWTToken = function(){
try {
var generatedtoken = jwt.sign({id: this._id}, "FULLSTACKWEBDEVELOPMENTMEANMERNBATCH")
// console.log(generatedtoken)
this.tokens = this.tokens.concat({token: generatedtoken})
this.save()
return generatedtoken
}
catch(err){
console.log(err)
return "false"
}
}
const userModel = mongoose.model('userModel', schema2)
module.exports = userModel
enter code here
You can control this login page rendering by checking you are valid login user or not. You can check this by a middleware function in your route file
const {isLoggedIn} = require("./middleware");
app.get("/login", isLoggedIn, (req, res)=>{
res.render("login");
})
app.get("/reg", isLoggedIn, (req, res)=>{
res.render("userRegister");
})
//For Logout from this session simply hit logout url
router.get('/logout', async (req, res) => {
res.clearCookie('node1')
res.redirect("/login");
});
where isLoggedIn is a middleware function which will check if you are an existing valid user or not
middleware.js
const jwt = require('jsonwebtoken');
module.exports.isLoggedIn = async(req,res, next)=>{
try{
const token = req.cookies ? req.cookies.node1 : null;
const decoded = token ? jwt.verify(token, "FULLSTACKWEBDEVELOPMENTMEANMERNBATCH") : null
if(decoded){
return res.redirect('/home');
}
console.log(decoded);
next();
}catch(err){
res.render("login");
}
}
Hoping this may work in your case

Why the user = await User.findOne({ email }) returns null?

I'm setting up a login route and I decided to test it with postman and it worked but later when I was checking my DB configuration I found an error when I fixed the error the login test on postman doesn't work
so in my server.js file I have :
const express = require("express");
const connectDB = require("./config/db");
const app = express();
// Connect to MongoDB
connectDB();
// Initialize middleware
app.use(express.json());
// Define routes
app.use("/api/users", require("./routes/users"));
app.use("/api/auth", require("./routes/auth"));
app.use("/api/posts", require("./routes/posts"));
app.use("/api/profile", require('./routes/profile'));
// Create server
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`Server started on port ${PORT}`));
The connectDB function in config/db.js :
const mongoose = require("mongoose");
require('dotenv').config()
const connectDB = async () => {
try {
await mongoose.connect(process.env.MONGO_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
useFindAndModify: false,
useCreateIndex: true
});
console.log("Successfully connected to MongoDB");
} catch (err) {
console.error(err.message);
}
};
module.exports = connectDB;
In the auth.js route :
const express = require("express");
const router = express.Router();
const { check } = require("express-validator");
const {auth} = require('../middlewares/auth');
const {login} = require('../controllers/authController');
// #route: POST api/auth
// #desc: Login
// #access: Public
router.post("/",
[
check("email", "Email is required").not().isEmpty(),
check("password", "Password is required").not().isEmpty(),
],
login
);
module.exports = router;
The Auth controller in controllers/authController.js :
const { validationResult } = require("express-validator");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
require('dotenv').config()
exports.login = async (req, res) => {
try {
// Check for validation errors
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
// Check if user exists
const { email, password } = req.body;
const user = await User.findOne({ email });
if (!user) {
return res.status(400).json({ msg: "Invalid credentials : you must register" });
}
// If exists, check password
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) {
return res.status(400).json({ msg: "Invalid credentials : wrong password" });
}
// Return jwt
const payload = {
user: {
id: user.id,
},
};
jwt.sign(payload,
process.env.JWT_SECRET,{expiresIn: 3600},(err, token) => {
if (err) throw err;
res.json({ token });
}
);
} catch (err) {
console.error(err.message);
res.status(500).send("There was an error with the server. Try again later.");
}
}
Everything looks great and when I try to login with postman it returns the "Invalid credentials : you must register" message from this code in authController.js ( when I console.log(user) it returns null ) :
const { email, password } = req.body;
const user = await User.findOne({ email });
if (!user) {
return res.status(400).json({ msg: "Invalid credentials : you must register" });
}
PS: At first, in the db configuration I forgot to add the mongo client options and everything worked and it returns the token in postman but after fixing the error I had the login problem

node.js req.body returning undefined

EDIT: #LawrenceCherone solved this, its (req, res, next) not (err, res, req)
I am creating a MERN app (Mongo, express, react, node).
I have some routes that work fine and return data from mongodb. However I created a new controller to access a separate collection and whenever i try to create a new document in it my req.body returns undefined.
I have setup my server.js like this:
const express = require("express");
const bodyParser = require("body-parser");
const cors = require("cors");
const connectDB = require("./db");
const app = express();
const apiPort = 3000;
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cors());
app.use(bodyParser.json());
connectDB();
app.use("/api", require("./routes/router"));
var server = app.listen(apiPort, () => console.log(`Server running on port ${apiPort}`));
module.exports = server;
My router looks like this:
const express = require("express");
const QuizController = require("../controllers/quiz-controller");
const UserController = require("../controllers/user-controller");
const router = express.Router();
// quiz routes
router.post("/quizzes", QuizController.createQuestion);
router.get("/quizzes", QuizController.getAllQuestions);
router.get("/quizzes/:quiz_name", QuizController.getQuestionsByQuiz);
router.get("/quizzes/questions/:question_id", QuizController.getQuestionById);
router.put("/quizzes/:question_id/edit", QuizController.updateQuestionById);
router.delete("/quizzes/:question_id", QuizController.deleteQuestionById);
// user routes
router.post("/users", UserController.createUser);
module.exports = router;
All of the /quizzes routes work perfectly fine and i have had no trouble accessing the body. The UserController.createUser method is almost identical to Quizcontroller.createQuestion too so I am very confused.
Here is the user-controller with the createUser function:
const User = require("../models/User");
createUser = async (err, res, req) => {
const body = req.body;
console.log(req.body);
console.log(req.params);
console.log(body);
if (!body) {
return res.status(400).json({
succes: false,
error: "You must provide a body",
});
}
try {
const newUser = new User(body);
console.log(newUser);
if (!newUser) {
return res.status(400).json({ success: false, error: err });
}
const user = await newUser.save();
return res
.status(200)
.json({ success: true, newUser: user, msg: "New user created" });
} catch (err) {
console.error(err.message);
res.status(500).send("Server error");
}
};
module.exports = { createUser };
Here is an image of the postman request I am using to try test this:
[1]: https://i.stack.imgur.com/UHAK5.png
And the user model:
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const UserSchema = new Schema({
name: {
type: String,
required: true,
},
emailAddress: {
type: String,
required: true,
},
permission: {
type: String,
required: true,
},
auth0Id: {
type: String,
required: true,
},
});
module.exports = mongoose.model("users", UserSchema);
The functional parameter order matters.
its
createUser = async (req, res, next) => // correct format
Not
createUser = async (err, res, req) // wrong format

Getting error: FATAL ERROR: jwtPrivateKey is not defined.'

I'm still having some exception errors about JSON web token Private Key. It says it's not defined but I think I already put the JSON web token private key and still throwing an error. I'm not sure where the problem is maybe in the user module or auth module or on the config. Please see the below code and any help would be appreciated.
//default.json
{
"jwtPrivateKey": "",
"db": "mongodb://localhost/vidly"
}
// test.json
{
"jwtPrivateKey": "1234",
"db": "mongodb://localhost/vidly_tests"
}
// config.js
const config = require('config');
module.exports = function() {
if (!config.get('jwtPrivateKey')) {
throw new Error('FATAL ERROR: jwtPrivateKey is not defined.');
}
}
// users.js
const auth = require('../middleware/auth');
const jwt = require('jsonwebtoken');
const config = require('config');
const bcrypt = require('bcrypt');
const _ = require('lodash');
const {User, validate} = require('../models/user');
const mongoose = require('mongoose');
const express = require('express');
const router = express.Router();
router.get('/me', auth, async (req, res) => {
const user = await User.findById(req.user._id).select('-password');
res.send(user);
});
router.post('/', async (req, res) => {
const { error } = validate(req.body);
if (error) return res.status(400).send(error.details[0].message);
let user = await User.findOne({ email: req.body.email });
if (user) return res.status(400).send('User already registered.');
user = new User(_.pick(req.body, ['name', 'email', 'password']));
const salt = await bcrypt.genSalt(10);
user.password = await bcrypt.hash(user.password, salt);
await user.save();
const token = user.generateAuthToken();
res.header('x-auth-token', token).send(.pick(user, ['id', 'name', 'email']));
});
module.exports = router;
// auth.js
const Joi = require('joi');
const bcrypt = require('bcrypt');
const _ = require('lodash');
const {User} = require('../models/user');
const mongoose = require('mongoose');
const express = require('express');
const router = express.Router();
router.post('/', async (req, res) => {
const { error } = validate(req.body);
if (error) return res.status(400).send(error.details[0].message);
let user = await User.findOne({ email: req.body.email });
if (!user) return res.status(400).send('Invalid email or password.');
const validPassword = await bcrypt.compare(req.body.password, user.password);
if (!validPassword) return res.status(400).send('Invalid email or password.');
const token = user.generateAuthToken();
res.send(token);
});
function validate(req) {
const schema = {
email: Joi.string().min(5).max(255).required().email(),
password: Joi.string().min(5).max(255).required()
};
return Joi.validate(req, schema);
}
module.exports = router;
// db.js
const winston = require('winston');
const mongoose = require('mongoose');
const config = require('config');
module.exports = function() {
const db = config.get('db');
mongoose.connect(db)
.then(() => winston.info(Connected to ${db}...));
}
// logging.js
const winston = require('winston');
// require('winston-mongodb');
require('express-async-errors');
module.exports = function() {
winston.handleExceptions(
new winston.transports.Console({ colorize: true, prettyPrint: true }),
new winston.transports.File({ filename: 'uncaughtExceptions.log' }));
process.on('unhandledRejection', (ex) => {
throw ex;
});
winston.add(winston.transports.File, { filename: 'logfile.log' });
// winston.add(winston.transports.MongoDB, {
// db: 'mongodb://localhost/vidly',
// level: 'info'
// });
}
// index.js
const winston = require('winston');
const express = require('express');
const app = express();
require('./startup/logging')();
require('./startup/routes')(app);
require('./startup/db')();
require('./startup/config')();
require('./startup/validation')();
const port = process.env.PORT || 3000;
app.listen(port, () => winston.info(Listening on port ${port}...));
// user.test.js
const {User} = require('../../../models/user');
const jwt = require('jsonwebtoken');
const config = require('config');
const mongoose = require('mongoose');
describe('user.generateAuthToken', () => {
it('should return a valid JWT', () => {
const payload = {
_id: new mongoose.Types.ObjectId().toHexString(),
isAdmin: true
};
const user = new User(payload);
const token = user.generateAuthToken();
const decoded = jwt.verify(token, config.get('jwtPrivateKey'));
expect(decoded).toMatchObject(payload);
});
});
// package.json
"scripts": {
"test": "jest --watchAll --verbose"
},
the structure of your config files are wrong. if u check the https://www.npmjs.com/package/config
this is the structure of file:
{
"Customer": {
"dbConfig": {
"host": "prod-db-server"
},
"credit": {
"initialDays": 30
}
}
}
that page also provides this info:
config.get() will throw an exception for undefined keys to help catch typos and missing values. Use config.has() to test if a configuration value is defined.
I think set does not work with visual studio code terminal. I had same issue, when i executed in Windows CMD it worked.
Try config.get instead of config.has()
module.exports = function() {
if (!config.has('jwtPrivateKey')) {
throw new Error('FATAL ERROR: jwtPrivateKey is not defined.');
}
if you are using mosh's tutorial as it said here you should have a file named custom-environment-variables.json too and it contains:
{
"jwtPrivateKey": "vidly_jwtPrivateKey"
}
then you have to set an environment variable called vidly_jwtPrivateKey.
in windows you can run this: set vidly_jwtPrivateKey=mySecureKey on CMD.
Hope it solves the problem :)
n
if(!config.has('jwtPrivateKey')) {
console.error("FATAL ERROR: jwtPrivateKey not defined.")
process.exit(1);
}
try to use config.has() instead of config.get()

Why is my Express api register route not POSTing?

I am trying to make a small authentication system for a practice project I have. I am trying to send POST requests via postman to my express server(http://localhost:4000/api/register), and it's replying back "404 not found" I am following the tutorial here.
Here is my server.js:
const newpost = require('./routes/newpost');
const getposts = require('./routes/getposts');
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const deleteposts = require('./routes/delete');
const editposts = require('./routes/editposts');
const path = require('path');
const app = express();
const webpack = require('webpack');
const webpackConfig = require('../webpack.config');
const webpackMiddleware = require('webpack-dev-middleware');
const webpackHotMiddleware = require('webpack-hot-middleware');
const passport = require('passport');
const port = 4000;
const compiler = webpack(webpackConfig);
const config = require('./config/main');
const mongoose = require('mongoose');
const authRouter = require('./routes/authrouter');
const logger = require('morgan');
// db connection
mongoose.connect(config.database);
app.use(passport.initialize());
/*
app.use(webpackMiddleware(compiler, {
noInfo: true, publicPath: webpackConfig.output.publicPath,
}));
app.use(webpackHotMiddleware(compiler, {
log: console.log,
}));
*/
app.use(cors());
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }));
// parse application/json
app.use(bodyParser.json());
app.use(logger('dev'));
app.use('/newpost', newpost);
app.use('/posts', getposts);
app.use('/delete', deleteposts);
app.use('/edit', editposts);
//auth router to handle auth routes
authRouter(app);
/*
app.get('/*', (req, res) => {
res.sendFile(path.join(__dirname, '../public/index.html'));
}); */
app.listen(port, () => {
console.log(`Listening on port ${port}`);
});
Here is my authrouter.js. These are the routes I'm exporting into my server.js. :
const AuthenticationController = require('../controllers/authentication');
const express = require('express');
// const passportService = require('../config/passport');
/* eslint-disable */
const passport = require('passport');
// Middleware to require login/auth
// const requireAuth = passport.authenticate('jwt', { session: false });
const requireLogin = passport.authenticate('local', { session: false });
module.exports = function(app){
"use-strict";
// init route groups
const apiRoutes = express.Router();
const authRoutes = express.Router();
// auth routes
// set auth routes as subgroup/middleware to apiRoutes
apiRoutes.use('/auth', authRoutes);
// Registration routes
authRoutes.post('/register', AuthenticationController.register);
// Login route
authRoutes.post('/login', requireLogin, AuthenticationController.login);
// Set url for API group routes
app.use('/api', apiRoutes);
};
Here is my authentication.js
const jwt = require('jsonwebtoken');
// const crypto = require('crypto'); used for pw resets
const User = require('../models/user');
const config = require('../config/main');
function generateToken(user) {
return jwt.sign(user, config.secret, {
expiresIn: 10080, // in seconds
});
}
// set user info from request
function setUserInfo(request) {
return {
_id: request._id,
email: request.email,
role: request.role,
};
}
// Login Route
exports.login = function (req, res, next) {
const userInfo = setUserInfo(req.user);
res.status(200).json({
token: `JWT${generateToken(userInfo)}`,
user: userinfo,
});
};
// registration route
exports.register = function (req, res, next) {
// check for registration errors
const email = req.body.email;
const password = req.body.password;
// Return error if no email provided
if (!email) {
return res.status(422).send({ error: 'You must enter an email address' });
}
// Return error if no pw provided
if (!password) {
return res.status(422).send({ error: 'You must enter a password' });
}
User.findOne({ email }, (err, existingUser) => {
if (err) { return next(err); }
// if user is not unique, return error
if (existingUser) {
return res.status(422).send({ error: 'That email address is already in use' });
}
// if email is unique and pw was provided, create acct
const user = new User({
email,
password,
});
user.save((err, user) => {
if (err) { return next(err); }
// Subscribe member to Mailchimp list
// mailchimp.subscribeToNewsLetter(user.email);
// Respond with JWT if user was created
const userInfo = setUserInfo(user);
res.status(201).json({
token: `JWT ${generateToken(userInfo)}`,
user: userInfo,
});
});
});
};
// Role authorization check
exports.roleAuthorization = function (role) {
return function (req, res, next) {
const user = req.user;
User.findById(user._id, (err, foundUser) => {
if (err) {
res.status(422).json({ error: 'No user was found' });
return next(err);
}
// if user is found, check role
if (foundUser.role == role) {
return next();
}
res.status(401).json({ error: 'You are not authorized to view this content ' });
return next('Unauthorized');
});
};
};
Here is my passport.js :
// Importing Passport; strategies; and config
const passport = require('passport');
const User = require('../models/user');
const config = require('./main');
const JwtStrategy = require('passport-jwt').Strategy;
const ExtractJwt = require('passport-jwt').ExtractJwt;
const LocalStrategy = require('passport-local');
const localOptions = { usernameField: 'email' };
// setting up the local Strategy
const localLogin = new LocalStrategy(localOptions, ((email, password, done) => {
User.findOne({ email }, (err, user) => {
if (err) { return done(err); }
if (!user) {
return done(null, false, { error: 'Your login details could not be verified. Please try again.',
});
}
user.comparePassword(password, (err, isMatch) => {
if (err) { return done(err); }
if (!isMatch) {
return done(null, false, { error: 'Your login details could not be verified. Please try again.',
});
}
return done(null, user);
});
});
}));
const jwtOptions = {
// Telling passport to check auth headers for JWT
jwtFromRequest: ExtractJwt.fromAuthHeader(),
// Telling passport where to find the secret
secretOrKey: config.secret,
};
// setting up JWT login strategy
const jwtLogin = new JwtStrategy(jwtOptions, ((payload, done) => {
User.findById(payload._id, (err, user) => {
if (err) { return done(err, false); }
if (user) {
done(null, user);
} else {
done(null, false);
}
});
}));
// allow passport to use the strategies we defined
passport.use(jwtLogin);
passport.use(localLogin);
I believe the correct post endpoint would be api/auth/register

Categories

Resources