-
Notifications
You must be signed in to change notification settings - Fork 265
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
node_modules | ||
.env |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
const express = require('express'); | ||
const app = express(); | ||
|
||
const authRouter = require('./router/authRoute.js'); | ||
const databaseconnect = require('./config/databaseConfig.js'); | ||
const cookieParser = require('cookie-parser'); | ||
const cors = require('cors'); | ||
|
||
// connect to db | ||
databaseconnect(); | ||
|
||
app.use(express.json()); // Built-in middleware | ||
app.use(cookieParser()); // Third-party middleware | ||
|
||
app.use(cors({ origin: [process.env.CLIENT_URL], credentials: true })); //Third-party middleware | ||
|
||
// Auth router | ||
app.use('/auth', authRouter); | ||
|
||
app.use('/', (req, res) => { | ||
res.status(200).json({ data: 'JWTauth server ;)' }); | ||
}); | ||
|
||
module.exports = app; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
const mongoose = require("mongoose"); | ||
require('dotenv').config(); | ||
const MONGODB_URL = | ||
process.env.MONGODB_URL || "mongodb://localhost:27017/my_database"; | ||
|
||
// mongoDb database connection | ||
const databaseconnect = () => { | ||
mongoose | ||
.connect(MONGODB_URL) | ||
.then((conn) => console.log(`connected to DB: ${conn.connection.host}`)) | ||
.catch((err) => console.log(err.message)); | ||
}; | ||
|
||
module.exports = databaseconnect; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
const userModel = require("../model/userSchema.js"); | ||
const bcrypt = require("bcrypt"); | ||
|
||
const emailValidator = require("email-validator"); | ||
|
||
/****************************************************** | ||
* @SIGNUP | ||
* @route /api/auth/signup | ||
* @method POST | ||
* @description singUp function for creating new user | ||
* @body name, email, password, confirmPassword | ||
* @returns User Object | ||
******************************************************/ | ||
|
||
const signUp = async (req, res, next) => { | ||
const { name, email, password, confirmPassword } = req.body; | ||
console.log(name , email,password,confirmPassword) | ||
Check failure Code scanning / CodeQL Use of externally-controlled format string High
Format string depends on a
user-provided value Error loading related location Loading Check failure Code scanning / CodeQL Clear-text logging of sensitive information High
This logs sensitive data returned by
an access to password Error loading related location Loading Check failure Code scanning / CodeQL Clear-text logging of sensitive information High
This logs sensitive data returned by
an access to confirmPassword Error loading related location Loading |
||
/// every field is required | ||
if (!name || !email || !password || !confirmPassword) { | ||
return res.status(400).json({ | ||
success: false, | ||
message: "Every field is required" | ||
}); | ||
} | ||
|
||
//validate email using npm package "email-validator" | ||
const validEmail = emailValidator.validate(email); | ||
if (!validEmail) { | ||
return res.status(400).json({ | ||
success: false, | ||
message: "Please provide a valid email address 📩" | ||
}); | ||
} | ||
|
||
try { | ||
/// send password not match err if password !== confirmPassword | ||
if (password !== confirmPassword) { | ||
return res.status(400).json({ | ||
success: false, | ||
message: "password and confirm Password does not match ❌" | ||
}); | ||
} | ||
|
||
const userInfo = new userModel(req.body); | ||
|
||
// userSchema "pre" middleware functions for "save" will hash the password using bcrypt | ||
// before saving the data into the database | ||
const result = await userInfo.save(); | ||
return res.status(200).json({ | ||
success: true, | ||
data: result | ||
}); | ||
} catch (error) { | ||
/// send the message of the email is not unique. | ||
if (error.code === 11000) { | ||
return res.status(400).json({ | ||
success: false, | ||
message: `Account already exist with the provided email ${email} 😒` | ||
}); | ||
} | ||
|
||
return res.status(400).json({ | ||
message: error.message | ||
}); | ||
} | ||
}; | ||
|
||
/****************************************************** | ||
* @SIGNIN | ||
* @route /api/auth/signin | ||
* @method POST | ||
* @description verify user and send cookie with jwt token | ||
* @body email , password | ||
* @returns User Object , cookie | ||
******************************************************/ | ||
|
||
const signIn = async (req, res, next) => { | ||
const { email, password } = req.body; | ||
console.log(email,password) | ||
Check failure Code scanning / CodeQL Use of externally-controlled format string High
Format string depends on a
user-provided value Error loading related location Loading Check failure Code scanning / CodeQL Clear-text logging of sensitive information High
This logs sensitive data returned by
an access to password Error loading related location Loading |
||
|
||
// send response with error message if email or password is missing | ||
if (!email || !password) { | ||
return res.status(400).json({ | ||
success: false, | ||
message: "email and password are required" | ||
}); | ||
} | ||
|
||
try { | ||
// check user exist or not | ||
const user = await userModel | ||
.findOne({ | ||
}) | ||
Check failure Code scanning / CodeQL Database query built from user-controlled sources High
This query object depends on a
user-provided value Error loading related location Loading |
||
.select("+password"); | ||
|
||
// If user is null or the password is incorrect return response with error message | ||
if (!user || !(await bcrypt.compare(password, user.password))) { | ||
// bcrypt.compare returns boolean value | ||
return res.status(400).json({ | ||
success: false, | ||
message: "invalid credentials" | ||
}); | ||
} | ||
|
||
// Create jwt token using userSchema method( jwtToken() ) | ||
const token = user.jwtToken(); | ||
user.password = undefined; | ||
|
||
const cookieOption = { | ||
secure:true, | ||
maxAge: 24 * 60 * 60 * 1000, //24hr | ||
httpOnly: true // not able to modify the cookie in client side | ||
}; | ||
|
||
res.cookie("token", token, cookieOption); | ||
res.status(200).json({ | ||
success: true, | ||
data: user | ||
}); | ||
} catch (error) { | ||
return res.status(400).json({ | ||
success: false, | ||
message: error.message | ||
}); | ||
} | ||
}; | ||
|
||
|
||
/****************************************************** | ||
* @LOGOUT | ||
* @route /api/auth/logout | ||
* @method GET | ||
* @description Remove the token form cookie | ||
* @returns logout message and cookie without token | ||
******************************************************/ | ||
|
||
const logout = async (req, res, next) => { | ||
try { | ||
const cookieOption = { | ||
expires: new Date(Date.now()), // current expiry date | ||
httpOnly: true // not able to modify the cookie in client side | ||
}; | ||
|
||
// return response with cookie without token | ||
res.cookie("token", null, cookieOption); | ||
res.status(200).json({ | ||
success: true, | ||
message: "Logged Out" | ||
}); | ||
} catch (error) { | ||
res.stats(400).json({ | ||
success: false, | ||
message: error.message | ||
}); | ||
} | ||
}; | ||
|
||
/****************************************************** | ||
* @GETUSER | ||
* @route /api/auth/user | ||
* @method GET | ||
* @description retrieve user data from mongoDb if user is valid(jwt auth) | ||
* @returns User Object | ||
******************************************************/ | ||
|
||
const getUser = async (req, res, next) => { | ||
const userId = req.user.id; | ||
try { | ||
const user = await userModel.findById(userId); | ||
return res.status(200).json({ | ||
success: true, | ||
data: user | ||
}); | ||
} catch (error) { | ||
return res.status(400).json({ | ||
success: false, | ||
message: error.message | ||
}); | ||
} | ||
}; | ||
|
||
module.exports = { | ||
signUp, | ||
signIn, | ||
|
||
getUser, | ||
|
||
logout | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
require('dotenv').config(); | ||
const PORT = process.env.PORT || 5000; | ||
|
||
|
||
const app = require('./app'); | ||
|
||
app.listen(PORT,()=>{ | ||
console.log(`server is listening at http://localhost:${PORT}`); | ||
}) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
const JWT = require("jsonwebtoken"); | ||
|
||
// router level middleware function | ||
const jwtAuth = (req, res, next) => { | ||
|
||
// get cookie token(jwt token generated using json.sign()) form the request | ||
const token = ( req.cookies?.token) || null; | ||
|
||
// return response if there is no token(jwt token attached with cookie) | ||
if (!token) { | ||
return res.status(400).json({ success: false, message: "NOT authorized" }); | ||
} | ||
|
||
// verify the token | ||
try { | ||
const payload = JWT.verify(token, process.env.SECRET); | ||
req.user = { id: payload.id, email: payload.email }; | ||
} catch (error) { | ||
return res.status(400).json({ success: false, message: error.message }); | ||
} | ||
next(); | ||
}; | ||
|
||
module.exports = jwtAuth; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
const mongoose = require('mongoose'); | ||
const { Schema } = mongoose; | ||
const crypto = require('crypto'); | ||
const bcrypt = require('bcrypt'); | ||
const JWT = require('jsonwebtoken'); | ||
|
||
const userSchema = new Schema( | ||
{ | ||
name: { | ||
type: String, | ||
require: [true, 'user name is Required'], | ||
|
||
trim: true, | ||
}, | ||
email: { | ||
type: String, | ||
required: [true, 'user email is required'], | ||
unique: true, | ||
lowercase: true, | ||
unique: [true, 'already registered'], | ||
}, | ||
password: { | ||
type: String, | ||
select: false, | ||
}, | ||
forgotPasswordToken: { | ||
type: String, | ||
}, | ||
forgotPasswordExpiryDate: { | ||
type: Date, | ||
}, | ||
}, | ||
{ timestamps: true } | ||
); | ||
|
||
// Hash password before saving to the database | ||
userSchema.pre('save', async function (next) { | ||
// If password is not modified then do not hash it | ||
if (!this.isModified('password')) return next(); | ||
this.password = await bcrypt.hash(this.password, 10); | ||
return next(); | ||
}); | ||
|
||
// FIXME: Check if these methods are working as expected | ||
userSchema.methods = { | ||
//method for generating the jwt token | ||
jwtToken() { | ||
return JWT.sign( | ||
{ id: this._id, email: this.email }, | ||
process.env.SECRET, | ||
{ expiresIn: '24h' } // 24 hours | ||
); | ||
}, | ||
|
||
//userSchema method for generating and return forgotPassword token | ||
getForgotPasswordToken() { | ||
const forgotToken = crypto.randomBytes(20).toString('hex'); | ||
//step 1 - save to DB | ||
this.forgotPasswordToken = crypto | ||
.createHash('sha256') | ||
.update(forgotToken) | ||
.digest('hex'); | ||
|
||
/// forgot password expiry date | ||
this.forgotPasswordExpiryDate = Date.now() + 20 * 60 * 1000; // 20min | ||
|
||
//step 2 - return values to user | ||
return forgotToken; | ||
}, | ||
}; | ||
|
||
const userModel = mongoose.model('user', userSchema); | ||
module.exports = userModel; |