EJS not rendering page on display - javascript

PLEASE SOMEONE
Below is the code for a login app that I was trying out, and as I'm sure you can gather I'm a real noob at this, I think I did everything right because there weren't any errors thrown, but I came across this problem, and its been killing me.
I've been wracking my brain for an answer I just can't get the ejs to render the view. Upon inspecting the network shows the fetch item to be correct but It just doesn't render.
obj.js
const form = document.getElementById('Signinform');
form.addEventListener('submit', Signin);
async function Signin(event){
event.preventDefault();
const email = document.getElementById('email').value
const password = document.getElementById('password').value
const result = await fetch('/user/signin',{
method:'POST',
headers:{
'Content-Type':'application/json',
'Accept': 'text/html'
},
body:JSON.stringify({
email,
password
})
})//.then((res)=>res.json())
//console.log(result)
};
User.js
const express = require('express');
const router =express.Router();
//mongodb user model
const user = require('./../models/user');
const bodyParser = require('body-parser');
//password handler
const bcrypt = require('bcrypt');
//making the router use request body as json
//Signup
router.post('/signup',(req,res)=>{
let{name, email, password, dateofBirth} = req.body;
name = name.trim();
email = email.trim();
password = password.trim();
dateofBirth = dateofBirth.trim();
if(name == "" || email == "" || password == "" || dateofBirth == ""){
res.json({
status:"FAILED",
message:"Empty input fields"
});
}else if(!/^[a-zA-Z]*$/.test(name)) {
res.json({
status:"FAILED",
message:"Invalid name entered"
});
}else if(!/^[\w-\.]+#([\w-]+\.)+[\w-]{2,4}$/.test(email)){
res.json({
status:"FAILED",
message:"Invalid name entered"
});
}else if(! new Date(dateofBirth).getTime()){
res.json({
status:"FAILED",
message:"Invalid date of Birth entered"
});
}else if(password.length < 8){
res.json({
status:"FAILED",
message:"Password is too short!!"
})
}else{
//Checking if user already exists
user.find({email}).then(result=>{
if (result.length){
//if user already exists
res.json({
status: "FAILED",
message: "User with the provided email still exists"
})
} else{
//Try to create a new user
//password handling
const saltRounds =10;
bcrypt.hash(password,saltRounds).then(hashedPassword =>{
const newUser = new user({
name,
email,
password:hashedPassword,
dateofBirth
});
newUser.save().then(result=>{
res.json({
status: "SUCCESS",
message:"Signup succesful",
data:result,
})
}).catch(err=>{
res.json({
status:"FAILED",
message:"An error occured while trying to save User"
})
})
}).catch(err=>{
res.json({
status:"FAILED",
message:"An error occured while hashing password!"
})
})
}
}).catch(err=>{
console.log(err);
res.json({
status:"FAILED",
message:"An error occurered while checking for existing user"
})
})
}
})
//Rendering Sign in page
router.get('/signin',async(req,res)=>{
res.render('user_signin');
});
//Signin
router.post('/signin', async(req,res)=>{
let{email, password}=req.body;
email = email.trim();
password = password.trim();
if(email == "" || password == ""){
res.json({
status:"FAILED",
message:"Empty Credentials supplied"
});
}else{
//Check if user exists
user.find({email})
.then(data =>{
if(data.length){
//user exists
const hashedPassword = data[0].password;
bcrypt.compare(password,hashedPassword).then(result=>{
if(result){
//password matches
// res.json({
// status:"SUCCESS",
// message:"Signin succesful",
// data : data
// });
res.render('signinsuccess',{name : data[0].name});
}else{
res.json({
status: "FAILED",
message: "Invalid password entered"
});
}
})
.catch(err=>{
res.json({
status: "FAILED",
message:"An error occured while comparing passwords"
})
})
}else{
res.json({
status:"FAILED",
message:"Invalid Credentials entered"
})
}
})
.catch(err=>{
res.json({
status:"FAILED",
message:"An error occured while checking for existing user"
})
})
}
})
module.exports = router;
server.js
var express = require('express');
//getting database
require('./config/db.js');
const app = require('express')();
const port = 3000;
app.set('view engine','ejs');
const UserRouter =require('./api/user');
app.use('/assets', express.static('assets'));
//For accepting post form data
const bodyparser = require('express').json;
app.use(bodyparser());
app.use('/user', UserRouter)
app.listen(port,()=>{
console.log(`Server running on port ${port}`);
})
PLEASE HELP

Related

Javascript Fetching failing for no reason

I'm trying to make a login form where it fetches from another website, although, it keeps erroring with Error: Failed to Fetch
I don't really notice anything wrong with the code, but maybe its something related to CORS
Here is my code (HTML, CSS, JavaScript)
// Values: UsernameVal is being tested as "Developer"
// PasswordVal is being tested as "AccessTest"
if (User.value != "") {
if (Password.value != "") {
setFormMessage(loginForm, "info", "Checking account credentials..") // Set form message is just a basic function to set a login status message
var UsernameVal = User.value
var PasswordVal = Password.value
function a(data) {
console.log(data)
if (data.success == true) {
setFormMessage(loginForm, "success", "Logging in..")
} else {
setFormMessage(loginForm, "error", "Invalid username or password")
}
}
try {
console.log(`https://mysite.repl.co/check?username=${UsernameVal}&password=${PasswordVal}/`)
fetch(`https://mysite.repl.co/check?username=${UsernameVal}&password=${PasswordVal}/`, {
method: 'GET',
headers: {
accept: 'application/json',
},
})
.then(data => {
a(data)
}).catch((error) => {
throw new Error(error)
})
} catch (e) {
throw new Error(`Error setting login form message: ${e}`)
}
} else {
setFormMessage(loginForm, "error", "No password input provided")
}
} else {
setFormMessage(loginForm, "error", "No username input provided")
}
});
This is the code on the other side (nodejs)
const express = require('express');
const app = express();
const router = express.Router();
const bodyParser = require("body-parser")
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
const fs = require('fs')
app.post('/user', function(req,res) {
res.set("Access-Control-Allow-Origin", "OriginForGettingData")
const username = req.body.username
const password = req.body.password
res.send(`Added to login (${username}: ${password}}) list`)
const table = require('./values.json').Logins;
table[username] = password;
const fileName = './values.json';
const file = require(fileName);
file.Logins = table;
fs.writeFile(fileName, JSON.stringify(file)).done(function writeJSON(err) {
if (err) return console.log(err);
});
console.log(`Post recieved from ${insert}. New table: ${table}`)
})
app.get('/check', function(req,res){
res.set("Access-Control-Allow-Origin", "OriginForGettingData")
const username = req.param("username")
const password = req.param("password")
const table = require('./values.json').Logins;
res.json({"success": table[username] === password})
})
app.listen(3000, () => {
console.log('server started');
});
/user and /check work fine, its just the fetching that fails
After modifying the CORS for Access-Control-Allow-Origin from OriginForGettingData to *, it allowed the request to go through

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client error occured while using redirect in nodejs

I am making a project where I am facing this error. What I wanted to do is that according to the condition it should redirect the server to the particular routes but getting this error.
routes.post("/check", (req, res) => {
console.log("/check");
// console.log(req.body);
username = req.body.username;
password = req.body.password;
console.log("Step 1");
console.log("Username:", username, "\n", "Password", password);
console.log(public);
for (let i in public) {
if (username === i && password === public[i]) {
console.log("Authenticated success");
res.redirect("/public");
} else {
res.redirect("/404");
}
}
res.redirect("/public");
});
Output is
/check
Step 1
Username: shivam2
Password 4321
{ shivam2: '4321', arjun2: 'dcba' }
Authenticated success
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
You should return in case of successful authentication:
routes.post("/check", (req, res) => {
console.log("/check");
// console.log(req.body);
username = req.body.username;
password = req.body.password;
console.log("Step 1");
console.log("Username:", username, "\n", "Password", password);
console.log(public);
for (let i in public) {
if (username === i && password === public[i]) {
console.log("Authenticated success");
return res.redirect("/public");
}
}
res.redirect("/404");
});
You're calling multiple redirects, one in each iteration of the loop, which causes the error. However, you don't need the loop at all - you can examine public[username] directly (logging removed for brevity's sake):
routes.post("/check", (req, res) => {
username = req.body.username;
password = req.body.password;
if (public[username] === password) {
console.log("Authenticated success");
res.redirect("/public");
} else {
res.redirect("/404");
}
});

Express app error: [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client

const router = require("express").Router();
const mongoose = require("mongoose");
const User = require("../models/Users");
const bcrypt = require("bcrypt");
const jwt = require("jsonwebtoken");
// Route 1: create new user at /api/createuser
router.post("/createuser", async (req, res) => {
try {
console.log(req.body);
const salt = await bcrypt.genSaltSync(10);
const hash = await bcrypt.hashSync(req.body.password, salt);
password = hash;
const user = new User({
name: req.body.name,
email: req.body.email,
password: password,
});
user
.save()
.then(() => {
res.json({ message: "User created successfully" });
})
.catch((err) => {
res.json({ message: "Error: " + err });
});
console.log(password);
} catch (err) {
res.json({ message: err });
}
});
// Route 2: Login user at /api/login
router.post("/login", async (req, res) => {
try {
console.log("login endpoint triggered");
const user = await User.findOne({ email: req.body.email });
if (!user) {
res.json({ message: "User does not exist" });
}
const passwordIsValid = await bcrypt.compare(
req.body.password,
user.password
);
if (!passwordIsValid) {
res.json({ message: "Invalid password" });
} else {
const data = {
id: user._id,
};
const token = await jwt.sign(data, process.env.SECRET);
res.json(token);
}
} catch (error) {
res.json({ message: error });
}
});
module.exports = router;
Whenever I am testing the login endpoint, my app crashes if i try to put incorrect password or unregistered email.
It says Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
I have only sent one response to the client even then it is showing this error.
In the terminal, it is showing error at catch block of login endpoint.
Can anyone look into it and tell me why am i getting this error.
Make sure that when the response is an error, the rest of the middleware is not executed any more. For example, put a return before the res.json statement:
if (!user) {
return res.json({ message: "User does not exist" });
}
Otherwise, the "Invalid password" json might get issued after this one, but two res.jsons in one response lead to the observed error.

Express Session Not updating from route files

I am trying to create a book tracker with the MERN stack. I want to save some information in session, that is, when user tries to register, he hits a route, where validation happens and an email is sent to check if email really exists. Now the username, email, password and a verification code, are saved in session (which is actually not working), so that the verify route can access it, and save the user to database is the verification code entered by the user is correct which was sent to the email. Now saving of the information is not working, here is my code:
app.js file (entry point)
import dotenv from "dotenv";
dotenv.config();
import express from "express";
import bodyParser from "body-parser";
import cors from "cors";
import mongoose from "mongoose";
import session from "express-session";
// import routes
import authRoutes from "./routes/auth.js";
// db config
mongoose
.connect(process.env.DB_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
})
.then(() => console.log("DB Connected"))
.catch((err) => console.log(err));
// constants
const app = express();
const port = process.env.PORT || 5001;
// middlewares
app.use(bodyParser.json());
app.use(cors());
app.use(
session({
secret: process.env.SECRET,
resave: true,
saveUninitialized: true,
expires: new Date(Date.now() + 3600000),
proxy: true,
})
);
// using routes
app.use("/api", authRoutes);
app.listen(port, () =>
console.log(`Server is running on http://localhost:${port}/`)
);
routes/auth.js (auth related routes)
import dotenv from "dotenv";
dotenv.config();
import express from "express";
import securePin from "secure-pin";
import { User } from "../models/user.js";
import { transporter } from "../config/nodemailer.js";
const router = express.Router();
function validateEmail(email) {
return /^\w+([\.-]?\w+)*#\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(email);
}
router.post("/register", (req, res) => {
const { username, email, password } = req.body;
//check email matches the pattern
if (!validateEmail(email)) {
return res.json({
status: "error",
message: "Email is not valid",
});
}
// check if email already exists
User.findOne({ email: email }, (err, user) => {
if (user) {
return res.json({
status: "error",
message: "Email already exists, please sign in",
});
}
});
// check username is taken
User.findOne({ username: username }, (err, user) => {
if (user) {
return res.json({
status: "error",
message: "Username already exists, please choose another one",
});
}
});
// check username is atleast 4 characters
if (username.length < 4) {
return res.json({
status: "error",
message: "Username must be atleast 4 characters",
});
}
// check if username contains invalid characters
if (username.match(/[^a-zA-Z0-9_]/)) {
return res.json({
status: "error",
message: "Username must not contain special characters or spaces",
});
}
// check password contains spaces
if (password.match(/\s/)) {
return res.json({
status: "error",
message: "Password must not contain spaces",
});
}
// check password is atleast 6 characters
if (password.length < 6) {
return res.json({
status: "error",
message: "Password must be atleast 6 characters",
});
}
// generate unique token
var charSet = new securePin.CharSet();
charSet.addLowerCaseAlpha().addUpperCaseAlpha().addNumeric().randomize();
const code = securePin.generateStringSync(6, charSet);
// save info in session
req.session.username = username;
req.session.email = email;
req.session.password = password;
req.session.code = code;
req.session.save();
// send token to user's email
const mailOptions = {
from: process.env.EMAIL_ADDRESS,
to: email,
subject: "no reply- book tracker confirmation",
text: `Your verification code is: ${code}.`,
};
transporter.sendMail(mailOptions, (err, info) => {
if (err) {
return res.json({
status: "error",
message: err.message.toString(),
});
}
return res.json({
status: "success",
message: "Email sent",
});
});
});
router.post("/register/verify", (req, res) => {
const { code } = req.body;
const { username, email, password } = req.session;
// check if code matches
if (code !== req.session.code) {
return res.json({
status: "error",
message: "Code is invalid",
});
}
// create user
const user = new User({
username,
email,
password,
});
// save user
// user.save((err) => {
// if (err) {
// return res.json({
// status: "error",
// message: err.message,
// });
// }
// return res.json({
// status: "success",
// message: "Account created successfully!",
// });
// });
console.log(user);
return res.json(user);
});
export default router;

node.js express-session + redis single instance issue

I'm using express-session module to handle my node.js user sessions.
By default it allows multiple sessions per user. I need limit one session per user. I came to the following solution: store user_id:session_id pairs in redis, when user logins check if session for that user_id exists and delete it then create a new one and save it to redis. Everything works excellent until I tried to stress test my server using siege. I emulated simultaneous 1000 login attempts and I see that some sessions are not cleared and still is in redis store.
This allow one user have several sessions. What am I doing wrong?
Please find some code below.
var FileStreamRotator = require('file-stream-rotator'),
app = require('express')(),
fs = require("fs"),
bodyParser = require('body-parser'),
config = require("./providers/config"),
morgan = require('morgan'), //HTTP request logger middleware for node.js
cookieParser = require('cookie-parser'),
redis = require('redis'),
session = require('express-session'),
redisStore = require('connect-redis')(session),
publicRouter = require('./routes/public.js')();
var port = process.env.PORT || config.port;
var client = redis.createClient();
app.disable('x-powered-by');
app.use(cookieParser(config.session.secret));
app.use(session(
{
secret: config.session.secret,
store: new redisStore({host: config.redis.host, port: config.redis.port, client: client}),
saveUninitialized: false, // don't create session until something stored,
resave: false // don't save session if unmodified
}
));
app.use(morgan('combined', {stream: accessLogStream}));
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
*****
app.all('/api/*', [require('./middlewares/validateRequest')]);
******
app.use('/api/public', publicRouter);
******
app.listen(port, function (err) {
if (!err) console.log('Find me on port ' + port + ' and say "Hello"');
else console.log(err);
});
auth.js
var User = require('./../models/user.js');
var Promise = require('bluebird');
var redis = require("./../providers/redis.js");
var util = require('util');
var auth = {
login: function (req, res) {
var login = req.body.login || '';
var password = req.body.password || '';
if (login === '') {
res.status(401);
res.json({
"status": 401,
"message": "login required"
});
return;
}
if (password === '') {
res.status(401);
res.json({
"status": 401,
"message": "password required"
});
return;
}
User.login(login, password)
.then(function (user) {
if (!user) {
res.status(401);
res.json({
"status": 401,
"message": "Incorrect login data."
});
}
return redis.get(util.format("usersess:%s", user.id))
.then(function (currentSession) {
if (currentSession === null) {
redis.set(util.format("usersess:%s", user.id), req.session.id)
.then(function () {
delete user.password;
req.session.user = user;
res.json({
"status": 200,
"message": "User successfully logged in."
});
});
} else {
if (currentSession !== req.session.id) {
return redis.del(util.format("sess:%s", currentSession))
.then(function () {
return redis.set(util.format("usersess:%s", user.id), req.session.id);
})
.then(function () {
delete user.password;
req.session.user = user;
res.json({
"status": 200,
"message": "User successfully logged in."
});
})
} else {
res.json({
"status": 200,
"message": "User successfully logged in."
});
}
}
})
})
.catch(function (err) {
console.log(err);
res.status(500);
res.json({
error: true,
data: {
message: err.message
}
});
});
},
logout: function (req, res) {
req.session.destroy(function (err) {
if (err) {
console.log("Can't destroy the session. See details below");
console.log(err);
res.status(500);
res.json({
"status": 500,
"message": err.message
})
} else {
res.status(200);
res.json({
"status": 200,
"message": "User successfully logged out."
})
}
});
}
};
module.exports = auth;
user model user.js
var Promise = require('bluebird'),
bcrypt = Promise.promisifyAll(require('bcrypt')),
db = require("./../providers/db.js");
var User = {
tableName: 'users',
login: function (login, password) {
if (!login || !password) throw new Error('login and password are both required');
return db.execStoredProcedure("user_get_by_login", [login.trim()])
.then(
function (rows) {
var user = rows[0][0];
return bcrypt.compareAsync(password, user.password)
.then(function (res) {
if (!res) user = null;
return user;
});
}
);
}
};
module.exports = User;
redis provider redis.js
var config = require('./../providers/config');
var Promise = require("bluebird"),
redis = require('promise-redis')(function(resolver) {
return new Promise(resolver);
}),
redisClient = redis.createClient(config.redis.port, config.redis.host),
util = require('util');
redisClient.on('connect', function () {
console.log(util.format('redis connected on %s:%s', config.redis.host, config.redis.port));
});
module.exports = redisClient;
I was unable to find the exact reason why some sessions are not deleted but after a lot of debugging and logs investigating I think it is due to node async nature. While mySQL getting operation require some time, some login actions could run in parallel and get the same values for current user session_id.
To solve this, I created middleware that check if current user session id is in redis store, if it is not--it just destroys the session and logout user asking for a new login attempt. This may be not a good solution but it completely solved the original issue.

Categories