Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modernising the auth app #174

Open
wants to merge 18 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
node_modules
.vscode/*
.vscode/*
config/.env
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
v20.6.0
5 changes: 5 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"singleQuote": true,
"semi": false,
"trailingComma": "none"
}
22 changes: 10 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Introduction

A Simple ToDo App is built using the MVC Architecture, we have also implemented "authorization" so folx can sign up, customize & personalize the app
A Simple ToDo App is built using the MVC Architecture, we have also implemented "authorization" so folx can sign up, customize & personalize the app

---

Expand All @@ -14,31 +14,29 @@ A Simple ToDo App is built using the MVC Architecture, we have also implemented

---

# Who is this for?
# Who is this for?

- It's for beginners & intermediates with little more experience, to help understand the various aspects of building a node app with some complex features

---

# Packages/Dependencies used
# Packages/Dependencies used

bcrypt, connect-mongo, dotenv, ejs, express, express-flash, express-session, mongodb, mongoose, morgan, nodemon, passport, passport-local, validator
bcrypt, connect-mongo, ejs, express, express-flash, express-session, mongodb, mongoose, morgan, passport, passport-local, validator

---

# Install all the dependencies or node packages used for development via Terminal

`npm install`
`npm install`

---

# Things to add

- Create a `.env` file and add the following as `key: value`
- PORT: 2121 (can be any port example: 3000)
- DB_STRING: `your database URI`
---

Have fun testing and improving it! 😎

- Create a `.env` file and add the following as `key: value`
- PORT: 2121 (can be any port example: 3000)
- DB_STRING: `your database URI`
***

Have fun testing and improving it! 😎
2 changes: 0 additions & 2 deletions config/.env

This file was deleted.

7 changes: 1 addition & 6 deletions config/database.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,7 @@ const mongoose = require('mongoose')

const connectDB = async () => {
try {
const conn = await mongoose.connect(process.env.DB_STRING, {
useNewUrlParser: true,
useUnifiedTopology: true,
useFindAndModify: false,
useCreateIndex: true
})
const conn = await mongoose.connect(process.env.DB_STRING, {})

console.log(`MongoDB Connected: ${conn.connection.host}`)
} catch (err) {
Expand Down
56 changes: 36 additions & 20 deletions config/passport.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,47 @@ const mongoose = require('mongoose')
const User = require('../models/User')

module.exports = function (passport) {
passport.use(new LocalStrategy({ usernameField: 'email' }, (email, password, done) => {
User.findOne({ email: email.toLowerCase() }, (err, user) => {
if (err) { return done(err) }
if (!user) {
return done(null, false, { msg: `Email ${email} not found.` })
}
if (!user.password) {
return done(null, false, { msg: 'Your account was registered using a sign-in provider. To enable password login, sign in using a provider, and then set a password under your user profile.' })
}
user.comparePassword(password, (err, isMatch) => {
if (err) { return done(err) }
if (isMatch) {
return done(null, user)
passport.use(
new LocalStrategy(
{ usernameField: 'email' },
async (email, password, done) => {
try {
const user = await User.findOne({ email: email.toLowerCase() })

if (!user) {
return done(null, false, { msg: `Email ${email} not found.` })
}

if (!user.password) {
return done(null, false, {
msg: 'Your account was registered using a sign-in provider. To enable password login, sign in using a provider, and then set a password under your user profile.'
})
}
user.comparePassword(password, (err, isMatch) => {
if (err) {
return done(err)
}
if (isMatch) {
return done(null, user)
}
return done(null, false, { msg: 'Invalid email or password.' })
})
} catch (error) {
return done(err)
}
return done(null, false, { msg: 'Invalid email or password.' })
})
})
}))

}
)
)

passport.serializeUser((user, done) => {
done(null, user.id)
})

passport.deserializeUser((id, done) => {
User.findById(id, (err, user) => done(err, user))
passport.deserializeUser(async (id, done) => {
try {
return done(null, await User.findById(id))
} catch (error) {
return done(error)
}
})
}
165 changes: 95 additions & 70 deletions controllers/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,95 +2,120 @@ const passport = require('passport')
const validator = require('validator')
const User = require('../models/User')

exports.getLogin = (req, res) => {
if (req.user) {
return res.redirect('/todos')
}
res.render('login', {
title: 'Login'
})
exports.getLogin = (req, res) => {
if (req.user) {
return res.redirect('/todos')
}
res.render('login', {
title: 'Login'
})
}

exports.postLogin = (req, res, next) => {
const validationErrors = []
if (!validator.isEmail(req.body.email))
validationErrors.push({ msg: 'Please enter a valid email address.' })
if (validator.isEmpty(req.body.password))
validationErrors.push({ msg: 'Password cannot be blank.' })

if (validationErrors.length) {
req.flash('errors', validationErrors)
return res.redirect('/login')
}

exports.postLogin = (req, res, next) => {
const validationErrors = []
if (!validator.isEmail(req.body.email)) validationErrors.push({ msg: 'Please enter a valid email address.' })
if (validator.isEmpty(req.body.password)) validationErrors.push({ msg: 'Password cannot be blank.' })

if (validationErrors.length) {
req.flash('errors', validationErrors)
req.body.email = validator.normalizeEmail(req.body.email, {
gmail_remove_dots: false
})

passport.authenticate('local', (err, user, info) => {
if (err) {
return next(err)
}
if (!user) {
req.flash('errors', info)
return res.redirect('/login')
}
req.body.email = validator.normalizeEmail(req.body.email, { gmail_remove_dots: false })

passport.authenticate('local', (err, user, info) => {
if (err) { return next(err) }
if (!user) {
req.flash('errors', info)
return res.redirect('/login')
req.logIn(user, (err) => {
if (err) {
return next(err)
}
req.logIn(user, (err) => {
if (err) { return next(err) }
req.flash('success', { msg: 'Success! You are logged in.' })
res.redirect(req.session.returnTo || '/todos')
})
})(req, res, next)
}

exports.logout = (req, res) => {
req.logout(() => {
console.log('User has logged out.')
req.flash('success', { msg: 'Success! You are logged in.' })
res.redirect(req.session.returnTo || '/todos')
})
})(req, res, next)
}

exports.logout = (req, res) => {
console.log('Session before logout:', req.session)
req.logout(() => {
console.log('User has logged out.')
req.session.destroy((err) => {
if (err) console.log('Error : Failed to destroy the session during logout.', err)
if (err)
console.log('Error : Failed to destroy the session during logout.', err)
req.user = null
res.redirect('/')
})
})
}

exports.getSignup = (req, res) => {
if (req.user) {
return res.redirect('/todos')
}

exports.getSignup = (req, res) => {
if (req.user) {
return res.redirect('/todos')
}
res.render('signup', {
title: 'Create Account'
res.render('signup', {
title: 'Create Account'
})
}

exports.postSignup = async (req, res, next) => {
const validationErrors = []
if (!validator.isEmail(req.body.email))
validationErrors.push({ msg: 'Please enter a valid email address.' })
if (!validator.isLength(req.body.password, { min: 8 }))
validationErrors.push({
msg: 'Password must be at least 8 characters long'
})
if (req.body.password !== req.body.confirmPassword)
validationErrors.push({ msg: 'Passwords do not match' })
if (validationErrors.length) {
req.flash('errors', validationErrors)
console.log(req.flash)
return res.redirect('../signup')
}

exports.postSignup = (req, res, next) => {
const validationErrors = []
if (!validator.isEmail(req.body.email)) validationErrors.push({ msg: 'Please enter a valid email address.' })
if (!validator.isLength(req.body.password, { min: 8 })) validationErrors.push({ msg: 'Password must be at least 8 characters long' })
if (req.body.password !== req.body.confirmPassword) validationErrors.push({ msg: 'Passwords do not match' })

if (validationErrors.length) {
req.flash('errors', validationErrors)
req.body.email = validator.normalizeEmail(req.body.email, {
gmail_remove_dots: false
})

try {
const existingUser = await User.findOne({
$or: [{ email: req.body.email }, { userName: req.body.userName }]
})

if (existingUser) {
req.flash('errors', {
msg: 'Account with that email address or username already exists.'
})
return res.redirect('../signup')
}
req.body.email = validator.normalizeEmail(req.body.email, { gmail_remove_dots: false })


const user = new User({
userName: req.body.userName,
email: req.body.email,
password: req.body.password
})

User.findOne({$or: [
{email: req.body.email},
{userName: req.body.userName}
]}, (err, existingUser) => {
if (err) { return next(err) }
if (existingUser) {
req.flash('errors', { msg: 'Account with that email address or username already exists.' })
return res.redirect('../signup')

await user.save()

req.logIn(user, (err) => {
if (err) {
return next(err)
}
user.save((err) => {
if (err) { return next(err) }
req.logIn(user, (err) => {
if (err) {
return next(err)
}
res.redirect('/todos')
})
req.flash('success', {
msg: 'Successfully signed up!'
})

res.redirect('/todos')
})
}
} catch (error) {
return next(error)
}
}
9 changes: 5 additions & 4 deletions controllers/home.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
module.exports = {
getIndex: (req,res)=>{
res.render('index.ejs')
}
}
getIndex: (req, res) => {
console.log('get index')
res.render('index.ejs')
}
}
Loading