I am submitting a form by using "POST" method. But, even when I submit the form using "POST" method, I can see the submitted form data in http headers(Request Payload). I'm also using crypto to hash the password. This is the same login system I have deployed to heroku Simple Login System
Request Payload ScreenShot
This is my backend User Model
const mongoose = require('mongoose')
const crypto = require('crypto')
const userSchema = new mongoose.Schema({
username:{
type : String,
max : 32,
trim : true,
required : true,
unique : true,
index : true,
lowercase :true
},
name:{
type : String,
max : 32,
trim : true,
required : true
},
email:{
type : String,
trim : true,
required : true,
unique : true,
lowercase : true
},
profile:{
type : String,
required : true,
},
hashed_password:{
type : String,
required : true,
},
salt : String,
about :{
type : String
},
role :{
type: Number,
default : 0
},
photo:{
data : Buffer,
contentType : String
},
instagram:{
type: String
},
resetPasswordLink : {
data : String,
default : ''
}
},{timestamp : true})
userSchema.virtual('password')
.set(function(password){
//create a temporary variable called _password
this._password = password;
//generate salt
this.salt = this.makeSalt()
//encrypt password
this.hashed_password = this.encryptPassword(password)
})
.get(function(){
return this._password;
})
userSchema.methods = {
authenticate: function(plainText){
return this.encryptPassword(plainText) === this.hashed_password;
},
encryptPassword :function(password){
if(!password) return ''
try{
return crypto.createHmac('sha1',this.salt)
.update(password)
.digest('hex')
}
catch(err) {
return ''
}
},
makeSalt : function(){
return Math.round(new Date().valueOf * Math.random() + '');
}
}
module.exports = mongoose.model('User',userSchema);
Controller Method
const shortId = require('shortid')
const jwt = require('jsonwebtoken')
const expressJwt = require('express-jwt')
exports.signup = (req,res) => {
User.findOne({email: req.body.email}).exec((err,user)=>{
if(user) {
return res.status(400)
.json({ error : 'Email already exist'})
}
const { name, email, password } = req.body
let username = shortId.generate()
let profile = `${process.env.CLIENT_URL}/profile/${username}`
let newUser = new User( { name, email , password, profile, username })
newUser.save((err,success)=>{
if(err){
return res.status(400)
.json({error: err})
}
// res.json({
// user:success
// })
res.json({ message: 'Signup Success ! Please return to the Login page' })
})
})
};
exports.signin = (req,res) =>{
const { email,password } = req.body;
// check if user exists
User.findOne({ email }).exec((err,user)=> {
if(err || !user ){
return res.status(400).json({
error : 'User with that email does not exist,Please Sign Up'
});
}
// user authentication
if(!user.authenticate(password)) {
return res.status(400).json({
error : 'Email and password do not match'
});
}
// generate a token and send to client
const token = jwt.sign({ _id: user._id},process.env.JWT_SECRET, {expiresIn : '1d'} )
res.cookie('token',token, { expiresIn:'2d' })
const { _id, username, name, email, role } = user;
return res.json({
token,
user : { _id, username, name, email, role }
})
});
}
exports.signout = (req,res)=> {
res.clearCookie("token")
res.json({ message: 'Successfully Signed Out' })
}
Related
I am trying to store a user in MongoDB but when I send a test request from postman the req.body successfully logged to the console but MongoDB throw an error of empty values I put a function to test if I got any value in the statistic function but I got nothing back
my schema :
{
profilePicture: {
type: String,
required: true,
},
username: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
password: {
type: String,
required: true,
},
},
{ timestamps: true }
);
my static function :
UserSchema.statics.signup = async function (
profilePicture,
username,
email,
password
) {
const exist = await this.findOne({ username });
if (exist) {
throw Error("username exist");
}
if (!password || !profilePicture || !username || !email) {
throw Error("missing");
}
// password are empty so hash don't work fix it first
// const salt = await bcrypt.genSalt(10);
// const hash = await bcrypt.hash(password, salt);
const user = await this.create({
username,
password,
profilePicture,
email,
});
return user;
};
const signupUser = async (req, res) => {
const { profilePicture, username, email, password } = req.body;
console.log(req.body);
try {
const user = await User.signup({
profilePicture,
username,
email,
password,
});
const token = createToken(user._id);
res.status(400).json({ username, token });
} catch (error) {
res.status(200).json({ error: error.message });
}
};
when I send a request from postman I got the req.body working but it shows that the fields are empty this function run
if (!password || !profilePicture || !username || !email) {
throw Error("missing");
}
i use body-parser and send data from postman with the same key name
Your static function takes in four parameters, but you are calling it with a single object.
Try changing the User.signup call to:
const user = await User.signup(
profilePicture,
username,
email,
password,
);
(without the { and }).
I am returning a response object with the user and jwt token whenever a user logs in. But I want to exclude the password field when the user is sent in the response.
Controller:
const loginUser = asyncHandler(async (req, res) => {
const { email, password } = req.body;
// Check for user email
const user = await User.findOne({ email });
if (user && (await bcrypt.compare(password, user.password))) {
res.json({
user: user,
token: generateToken(user._id),
});
} else {
res.status(400);
throw new Error("Invalid credentials");
}
});
if I exclude the password when finding the user like this:
const user = await User.findById(decoded.id).select("-password");
Then bcrypt's compare method will not work as it needs user.password.
Please tell me how I can exclude password from user object in JSON response?
You can set undefined to the user before returning the user.
const loginUser = asyncHandler(async (req, res) => {
const { email, password } = req.body;
// Check for user email
const user = await User.findOne({ email });
if (user && (await bcrypt.compare(password, user.password))) {
user.password = undefined;
res.json({
user: user,
token: generateToken(user._id),
});
} else {
res.status(400);
throw new Error('Invalid credentials');
}
});
Or you can use the toJSON method in the user schema to exclude password:
const userSchema = new mongoose.Schema(
{
email: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
required: true,
},
},
{
toJSON: {
transform(doc, ret) {
delete ret.password;
},
},
},
);
I am building a user signup and login api and admin signup and login using express and currently I am testing in the postman, but somehow postman keeps return "error": "firstName is not defined" even though I posted firstname etc. here is my code, can anyone help me to explain it what is wrong? I saw so many videos using all different kinds of method, like generateAuthtakoken in the user.model or joi password library, it is just so overwhelming, can you help me to point to a direction as to how to use express to create ?
this is my user.model file:
const mongoose = require("mongoose");
const bcrypt = require("bcrypt");
const validator = require("validator");
const userSchema = new mongoose.Schema(
{
firstName: {
type: String,
required: true,
trim: true,
},
lastName: {
type: String,
required: true,
trim: true,
},
email: {
type: String,
required: true,
trim: true,
unique: true,
},
password: {
type: String,
required: true,
},
role: {
type: String,
enum: ["user", "admin"],
default: "user",
},
contactNumber: { type: String },
profilePicture: { type: String },
},
{ timestamps: true }
);
//static signup method
userSchema.statics.signup = async function (email, password) {
//validation
if (!firstName || !lastName || !email || !password) {
throw Error("All fields must be filled");
}
if (!validator.isEmail(email)) {
throw Error("Email is not valid");
}
if (!validator.isStrongPassword(password)) {
throw Error("Password is not strong enough");
}
const exists = await this.findOne({ email });
if (exists) {
throw Error("Email already in use");
}
const salt = await bcrypt.genSalt(10);
const hash = await bcrypt.hash(password, salt);
const user = await this.create({ email, password: bcrypt.hash });
return user;
};
//static login method
userSchema.statics.login = async function (email, password) {
if (!firstName || !lastName || !email || !password) {
throw Error("All fields must be filled");
}
const user = await this.findOne({ email });
if (!user) {
throw Error("Incorrect Email");
}
const match = await bcrypt.compare(password, user.password);
if (!match) {
throw Error("Incorrect password");
}
return user;
};
module.exports = mongoose.model("User", userSchema);
this is my controller file:
const User = require("../models/user");
const jwt = require("jsonwebtoken");
const createToken = (_id) => {
jwt.sign({ _id }, process.env.JWT_SECRET, { expiresIn: "3d" });
};
//login user
const loginUser = async (req, res) => {
const { email, password } = req.body;
try {
const user = await User.login(email, password);
// create token
const token = createToken(user._id);
res.status(200).json({ email, token });
} catch (error) {
res.status(400).json({ error: error.message });
}
res.json({ msg: "login user" });
};
//signup user
const signupUser = async (req, res) => {
const { email, password } = req.body;
try {
const user = await User.signup(email, password);
// create token
const token = createToken(user._id);
res.status(200).json({ email, token });
} catch (error) {
res.status(400).json({ error: error.message });
}
res.json({ msg: "login user" });
};
module.exports = { signupUser, loginUser };
and my router file:
const express = require("express");
const router = express.Router();
const { signupUser, loginUser } = require("../controller/auth");
//login route
router.post("/login", loginUser);
//signup route
router.post("/signup", signupUser);
module.exports = router;
where exactly do you get this error. Please provide full details to regenerate this error.
But as i could guess
In your static login method you do not need firstName and LastName.
In your signup user method you should be passing those missing required db fields as in your model.
I'm facing this problem since couple of days where I'm trying to insert the data into mongodb using mongoose but not able to get the data in mongodb. Below is the schema that I have created
const mongoose = require('mongoose')
const db = require('../db/db')
const crypto = require('crypto')
const { v4 : uuidv4 } = require('uuid');
const validator = require('validator')
// const { stringify } = require('querystring')
const schema = mongoose.Schema
const userSchema = new schema({
ObjId: schema.Types.ObjectId,
name : {
type : String,
trim: true,
required : true,
maxlength: 32
},
email : {
type : String,
trim: true,
required : true,
validate(value) {
if(!validator.isEmail(value)){
throw new Error ('The Email you have entered is not correct. Please enter the correct Email ID')
}
}
},
hashed_password : {
type : String,
required : true,
},
about : {
type : String,
trim: true,
required: true
},
salt : String,
user_roles: {
type: Number,
default: 0,
required: true
},
history : {
type: Array,
default: []
},
// timestamps: {
// createdAt : '',
// updatedAt : {type : Date, default : Date.now()},
// },
}, {timestamps: true})
// added virtual field
userSchema.virtual('password')
.set((password) =>{
this.password = password,
this.salt = uuidv4()
this.hashed_password = this.encryptPassword(password)
})
.get(() => {
return this._password
})
userSchema.methods = {
encryptPassword : (password) => {
if(!password) return ''
try {
return crypto.createHmac('sha256', this.salt)
.update(password)
.digest("hex")
}
catch(error) {
if(error) {
console.log('Found an Error in Line 70 in User.Js', error.message)
}
}
}
}
module.exports = mongoose.model("User", userSchema);
This is how I'm connecting the db
const mongoose = require('mongoose')
require('dotenv').config
// const connectionURL = 'mongodb://127.0.0.1:27017'
//const databaseName = 'ecommerce_db'
mongoose.connect(
// connectionURL,
process.env.MONGOURI,
{
useNewUrlParser: true,
useCreateIndex: true,
useUnifiedTopology: true
}
)
// .then((result) => { console.log('Mongo DataBase Connected', result)})
.then(() => { console.log('Mongo DataBase Connected')})
.catch((err) => {console.log('Mongoose Connection Failed', err)})
and this is where I'm saving the data
const User = require('../models/user')
const { response } = require('express')
const mongoose = require('mongoose')
exports.signUp = (req, res) => {
console.log('[Logging]', req.body)
// const user = new User({
// _id: mongoose.Schema.Types.ObjectId(),
// name: req.body.name,
// email: req.body.email,
// password: req.body.hashed_password
// })
const user = new User(req.body)
user.save((error, response) => {
if(error) {
return res.status(400).json({
error
})
}
res.json({
user
})
})
}
I'm getting all the correct input and success messages but still I'm not able to get the data inside mongodb, am I doing something wrong
I want to ask a question. I'm developing an app using sails.js and PostgreSQL (using sails-postgresql module). I'm using UUID for my primary key type instead of integer. But there are some error when I try to insert a data to my database.
my model UserModel.js
var uuid = require('node-uuid');
module.exports = {
adapter: 'somePostgresqlServer',
autoPK: false,
migrate: 'safe',
attributes: {
ID: {
primaryKey: true,
type: 'string',
defaultsTo: function (){
return uuid.v4();
},
unique: true,
index: true,
uuidv4: true
},
username: {
type: 'string',
required: true,
unique: true
}
}
};
my create function in the controller
create: function(req, res) {
if (!req.param('_username') || !req.param('_newPassword') ||
!req.param('_confirmPassword') || !req.param('_emailAddress') ||
!req.param('_firstName') || !req.param('_lastName')) {
var errorMessage = ["All field are required to sign up"];
req.session.flash = {
err : errorMessage
}
res.redirect('/login');
return;
}
if (req.param('_newPassword') != req.param('_confirmPassword')) {
var errorMessage = ["New password and confirm password must be same"];
req.session.flash = {
err : errorMessage
}
res.redirect('/login');
return;
}
UserModel.create({
username: req.param('_username'),
encryptedPassword: req.param('_newPassword'),
emailAddress: req.param('_emailAddress'),
firstName: req.param('_firstName'),
lastName: req.param('_lastName')
}).exec(function(err,post) {
if (err) {
return res.error();
}
res.redirect('/');
})
res.redirect('/');
}
the error
/home/***/***/***/node_modules/sails-postgresql/lib/adapter.js:393
Object.keys(collection.schema).forEach(function(schemaKey) {
^
TypeError: Object.keys called on non-object
at Function.keys (native)
at __CREATE__ (/home/***/***/***/node_modules/sails-postgresql/lib/adapter.js:393:16)
at after (/home/***/***/***/node_modules/sails-postgresql/lib/adapter.js:1155:7)
at /home/***/***/***/node_modules/sails-postgresql/lib/adapter.js:1049:7
at /home/***/***/***/node_modules/sails-postgresql/node_modules/pg/lib/pool.js:77:9
at dispense (/***/***/***/node_modules/sails-postgresql/node_modules/pg/node_modules/generic-pool/lib/generic-pool.js:250:16)
at Object.me.acquire (/home/***/***/***/node_modules/sails-postgresql/node_modules/pg/node_modules/generic-pool/lib/generic-pool.js:319:5)
at Object.pool.connect (/home/***/***/***/node_modules/sails-postgresql/node_modules/pg/lib/pool.js:71:12)
at PG.connect (/home/***/***/***/node_modules/sails-postgresql/node_modules/pg/lib/index.js:49:8)
at spawnConnection (/home/***/***/***/node_modules/sails-postgresql/lib/adapter.js:1048:8)
at Object.module.exports.adapter.create (/home/***/***/***/node_modules/sails-postgresql/lib/adapter.js:361:7)
at module.exports.create (/usr/lib/node_modules/sails/node_modules/waterline/lib/waterline/adapter/dql.js:84:13)
at bound.createValues (/usr/lib/node_modules/sails/node_modules/waterline/lib/waterline/query/dql/create.js:214:16)
at /usr/lib/node_modules/sails/node_modules/waterline/lib/waterline/query/dql/create.js:74:20
at /usr/lib/node_modules/sails/node_modules/waterline/node_modules/async/lib/async.js:708:13
at /usr/lib/node_modules/sails/node_modules/waterline/node_modules/async/lib/async.js:49:16
I wish you can help me. Thanks for your attention :)
Try this:
Model
var uuid = require('node-uuid');
module.exports = {
adapter: 'somePostgresqlServer',
autoPK: false,
attributes: {
id: {
primaryKey : true,
type : 'string',
defaultsTo : function (){
return uuid.v4();
},
unique : true,
index : true
},
username: {
type : 'string',
required : true,
unique : true
}
}
};
Controller
create: function(req, res) {
var username = req.param('_username'),
newPassword = req.param('_newPassword'),
confirmPassword = req.param('_confirmPassword'),
emailAddress = req.param('_emailAddress'),
firstName = req.param('_firstName'),
lastName = req.param('_lastName');
if (!(username || newPassword || confirmPassword || emailAddress || firstName || lastName)) {
var errorMessage = ["All field are required to sign up"];
req.session.flash = {
err : errorMessage
}
return res.redirect('/login');
}
if (newPassword != confirmPassword) {
var errorMessage = ["New password and confirm password must be same"];
req.session.flash = {
err : errorMessage
}
return res.redirect('/login');
}
UserModel
.create({
username : username,
encryptedPassword : newPassword,
emailAddress : emailAddress,
firstName : firstName,
lastName : lastName
})
.then(function(post) {
res.redirect('/');
})
.catch(res.negotiate);
}
At models definition, there are no exist migrate, it's on model configuration.
uuidv4 also not a valid attribute.
id field is necessary while you use Blueprint API, look after blueprint hooks at actionUtil in your sails at node_modules.
Don't call res.redirect at the end of controller while you have async. process, it will give race condition when query not completed yet and you will get redirected.
Actually I don't pretty sure if it will solve your problem, but you can try it and give a result later.