Skip to content
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 .env
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
PORT=3000
PORT=3000
SESS_SECRET = 'super saiyan 3'
4 changes: 4 additions & 0 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const app = express();

// ℹ️ This function is getting exported from the config folder. It runs most middlewares
require('./config')(app);
require('./config/sessions.config')(app);

// default value for title local
const projectName = 'lab-express-basic-auth';
Expand All @@ -28,6 +29,9 @@ app.locals.title = `${capitalized(projectName)}- Generated with Ironlauncher`;
const index = require('./routes/index');
app.use('/', index);

const signup = require('./routes/auth.routes')
app.use('/', signup)

// ❗ To handle errors. Routes that don't exist or errors that you handle in specific routes
require('./error-handling')(app);

Expand Down
32 changes: 32 additions & 0 deletions config/sessions.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// config/session.config.js

// require session
const session = require('express-session');
const MongoStore = require('connect-mongo');

// since we are going to USE this middleware in the app.js,
// let's export it and have it receive a parameter
module.exports = app => {
// <== app is just a placeholder here
// but will become a real "app" in the app.js
// when this file gets imported/required there

// required for the app when deployed to Heroku (in production)
app.set('trust proxy', 1);

// use session
app.use(
session({
secret: process.env.SESS_SECRET,
resave: true,
saveUninitialized: true,
store: MongoStore.create({ mongoUrl: process.env.MONGODB_URI || "mongodb://127.0.0.1:27017/lab-express-basic-auth" }),
cookie: {
sameSite: process.env.NODE_ENV === 'production' ? 'none' : 'lax',
secure: process.env.NODE_ENV === 'production',
httpOnly: true,
maxAge: 600000 // 600 * 1000 ms === 10 min
}
})
);
};
24 changes: 24 additions & 0 deletions middleware/route-guard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// middleware/route-guard.js

// checks if the user is logged in when trying to access a specific page
const isLoggedIn = (req, res, next) => {
if (!req.session.currentUser) {
return res.redirect('/login');
}
next();
};

// if an already logged in user tries to access the login page it
// redirects the user to the home page
const isLoggedOut = (req, res, next) => {
if (req.session.currentUser) {
return res.redirect('/');
}
next();
};

module.exports = {
isLoggedIn,
isLoggedOut
};

37 changes: 26 additions & 11 deletions models/User.model.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,29 @@
const { Schema, model } = require("mongoose");
// models/User.model.js
const { Schema, model } = require('mongoose');

// TODO: Please make sure you edit the user model to whatever makes sense in this case
const userSchema = new Schema({
username: {
type: String,
unique: true
const userSchema = new Schema(
{
username: {
type: String,
trim: true,
required: [true, 'Username is required.'],
unique: true
},
email: {
type: String,
required: [true, 'Email is required.'],
unique: true,
lowercase: true,
trim: true
},
passwordHash: {
type: String,
required: [true, 'Password is required.']
}
},
password: String
});
{
timestamps: true
}
);

const User = model("User", userSchema);

module.exports = User;
module.exports = model('User', userSchema);
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@
"dev": "nodemon server.js"
},
"dependencies": {
"bcryptjs": "^2.4.3",
"connect-mongo": "^5.1.0",
"cookie-parser": "^1.4.5",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"express-session": "^1.18.0",
"hbs": "^4.1.1",
"mongoose": "^6.1.2",
"morgan": "^1.10.0",
Expand Down
104 changes: 102 additions & 2 deletions public/stylesheets/style.css
Original file line number Diff line number Diff line change
@@ -1,8 +1,108 @@
/* public/stylesheets/style.css */
body {
padding: 50px;
font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
font: 14px 'Lucida Grande', Helvetica, Arial, sans-serif;
}

a {
color: #00B7FF;
color: #00b7ff;
text-decoration: none;
font-size: 1.5em;
}

form {
margin: 30px auto;
width: 380px;
}

form label {
color: #666;
display: inline-block;
margin-bottom: 10px;
text-align: center;
width: 100%;
}

form input,
form button {
box-sizing: border-box;
font-size: 14px;
outline: 0;
padding: 4px;
width: 100%;
margin-bottom: 20px;
}

form button {
background: #43a3e6;
border: 1px solid #43a3e6;
border-radius: 4px;
color: #fff;
cursor: pointer;
display: inline-block;
font-size: 14px;
padding: 8px 16px;
text-decoration: none;
text-transform: uppercase;
transition: 0.3s ease background;
width: 100%;
}

form button:hover {
background: #fff;
color: #43a3e6;
transition: 0.3s ease background;
}

.error {
background: #f02b63;
box-sizing: border-box;
color: #fff;
margin: 20px auto;
padding: 20px;
width: 100%;
}

ul {
border-bottom: 2px solid #43a3e6;
height: 30px;
padding: 1em 0;
list-style-type: none;
}

ul li {
line-height: 20px;
}

#to-right {
padding: 1em;
float: right;
}

#to-right span {
color: #43a3e6;
font-size: 1.5em;
}

#form h2 {
display: flex;
justify-content: center;
}

#to-left {
float: left;
}

#to-left p a {
color: #000;
font-weight: bold;
font-size: 2em;
}

#logout-form {
display: inline;
}

#logout-form button {
width: 120px;
}
77 changes: 77 additions & 0 deletions routes/auth.routes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
const router = require("express").Router();
const bcryptjs = require('bcryptjs');
const User = require('../models/User.model')
const { isLoggedIn, isLoggedOut } = require('../middleware/route-guard.js');
const saltRounds = 10;


/* GET home page */
router.get("/signup",isLoggedOut, (req, res, next) => {
res.render("auth/signup");
});

router.post('/signup',isLoggedOut, (req, res, next) => {
const { username, email, password } = req.body;

bcryptjs
.genSalt(saltRounds)
.then(salt => bcryptjs.hash(password, salt))
.then(hashedPassword => {
return User.create({
username,
email,
passwordHash: hashedPassword
});
})
.then(userFromDB => {
/* console.log('Newly created user is: ', userFromDB); */
res.redirect(`/userProfile`);
})
.catch(error => next(error));
});

router.get('/userProfile',isLoggedIn, (req, res) => {
console.log('req.session', req.session)
res.render('auth/user', {user: req.session.currentUser})
});

router.get('/login',isLoggedOut, (req, res, next) => {
res.render("auth/login")
});

router.post('/login',isLoggedOut, (req, res, next) => {
console.log('SESSION =====> ', req.session);
const { email, password } = req.body;
if (email === '' || password === '') {
res.render('auth/login', {
errorMessage: 'Please enter both, email and password to login.'
});
return;
}
User.findOne({ email })
.then(user => {
if (!user) {
console.log("Email not registered. ");
res.render('auth/login', { errorMessage: 'User not found and/or incorrect password.' });
return;
} else if (bcryptjs.compareSync(password, user.passwordHash)) {
req.session.currentUser = user;
res.redirect('/userProfile');
} else {
console.log("Incorrect password. ");
res.render('auth/login', { errorMessage: 'User not found and/or incorrect password.' });
}
})
.catch(error => next(error));
});

router.post('/logout',isLoggedIn, (req, res, next) => {
req.session.destroy(err => {
if (err) next(err);
res.redirect('/');
});
});



module.exports = router;
2 changes: 2 additions & 0 deletions routes/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ router.get("/", (req, res, next) => {
res.render("index");
});



module.exports = router;
22 changes: 22 additions & 0 deletions views/auth/login.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{{!-- views/auth/login.hbs --}}

<div id="form">
<h2>Login</h2>

<form action="/login" method="POST">

<label> Email
<input type="email" name="email" placeholder="rockstar@ironhack.com" />
</label>

<label>Password
<input type="password" name="password" placeholder="********" />
</label>

<button type="submit">Login</button>

{{#if errorMessage}}
<p class="error">{{errorMessage}}</p>
{{/if}}
</form>
</div>
23 changes: 23 additions & 0 deletions views/auth/signup.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{{!-- views/auth/signup.hbs --}}

<div id="form">
<h2>Signup</h2>
<form action="/signup" method="POST">

<label> Username
<input type="text" name="username" placeholder="ironhacker" />
</label>

<label> Email
<input type="email" name="email" placeholder="rockstar@ironhack.com" />
</label>

<label> Password
<input type="password" name="password" placeholder="********" />
</label>

<button type="submit">Create account</button>

{{!-- error message will be added here --}}
</form>
</div>
14 changes: 14 additions & 0 deletions views/auth/user.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{{!-- views/users/user-profile.hbs --}}

{{#if user}}
<h2>Welcome, {{ user.username }}!</h2>
<p>This is your profile page my friend!</p>
<button>
<a href="/userProfile">Reload the page</a>
</button>
<form id="logout-form" action="/logout" method="POST">
<button>Logout</button>
</form>
{{else}}
<p>Still no logged in user, sorry!</p>
{{/if}}
Loading