Added user model; added pages to register a new account, login and logout; added middleware to process whether a user is logged in or not
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
This commit is contained in:
parent
8c1c43e4df
commit
9a13319948
@ -19,6 +19,12 @@ a{
|
||||
}
|
||||
}
|
||||
|
||||
header{
|
||||
h1{
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.button.button-primary,
|
||||
button.button-primary,
|
||||
input[type="button"].button-primary,
|
||||
@ -56,6 +62,7 @@ input[type="submit"].button-primary{
|
||||
}
|
||||
.nav-bar-right{
|
||||
float: right;
|
||||
margin-right: 35px;
|
||||
}
|
||||
|
||||
ul{
|
||||
|
10
index.js
10
index.js
@ -42,6 +42,10 @@ app.use(express.urlencoded({
|
||||
extended: true,
|
||||
}));
|
||||
|
||||
// load middleware
|
||||
const userSessionMiddleware = require('./src/middleware/user-session');
|
||||
app.use(userSessionMiddleware.userSession);
|
||||
|
||||
// load the template engine
|
||||
app.set('view engine', 'twig');
|
||||
|
||||
@ -50,12 +54,18 @@ app.use(express.static('public'));
|
||||
|
||||
// load route handlers
|
||||
const homeRoutes = require('./src/routes/home');
|
||||
const authRoutes = require('./src/routes/auth');
|
||||
const itemRoutes = require('./src/routes/item');
|
||||
const licenseRoutes = require('./src/routes/license');
|
||||
const searchRoutes = require('./src/routes/search');
|
||||
|
||||
// register route handlers
|
||||
app.get('/', homeRoutes.getIndex);
|
||||
app.get('/auth/register', authRoutes.getRegister);
|
||||
app.post('/auth/register', authRoutes.postRegister);
|
||||
app.get('/auth/login', authRoutes.getLogin);
|
||||
app.post('/auth/login', authRoutes.postLogin);
|
||||
app.get('/auth/logout', authRoutes.getLogout);
|
||||
app.get('/item/add', itemRoutes.getAdd);
|
||||
app.post('/item/add', itemRoutes.postAdd);
|
||||
app.get('/item/:id', itemRoutes.getItem);
|
||||
|
44
migrations/0003_add_users_table.js
Normal file
44
migrations/0003_add_users_table.js
Normal file
@ -0,0 +1,44 @@
|
||||
module.exports = {
|
||||
up: (queryInterface, Sequelize) => {
|
||||
return queryInterface.createTable('users', {
|
||||
id: {
|
||||
allowNull: false,
|
||||
autoIncrement: true,
|
||||
primaryKey: true,
|
||||
type: Sequelize.INTEGER
|
||||
},
|
||||
username: {
|
||||
type: Sequelize.DataTypes.STRING,
|
||||
allowNull: false,
|
||||
unique: true,
|
||||
},
|
||||
email: {
|
||||
type: Sequelize.DataTypes.STRING,
|
||||
allowNull: false,
|
||||
unique: true,
|
||||
},
|
||||
password: {
|
||||
type: Sequelize.DataTypes.STRING,
|
||||
allowNull: false,
|
||||
},
|
||||
salt: {
|
||||
type: Sequelize.DataTypes.STRING,
|
||||
allowNull: false,
|
||||
},
|
||||
firstName: {
|
||||
type: Sequelize.DataTypes.STRING,
|
||||
allowNull: true,
|
||||
},
|
||||
lastName: {
|
||||
type: Sequelize.DataTypes.STRING,
|
||||
allowNull: true,
|
||||
},
|
||||
createdAt: Sequelize.DataTypes.DATE,
|
||||
updatedAt: Sequelize.DataTypes.DATE,
|
||||
});
|
||||
},
|
||||
|
||||
down: (queryInterface, Sequelize) => {
|
||||
return queryInterface.dropTable('users');
|
||||
}
|
||||
};
|
18
src/middleware/user-session.js
Normal file
18
src/middleware/user-session.js
Normal file
@ -0,0 +1,18 @@
|
||||
const db = require('../models');
|
||||
const User = db.users;
|
||||
|
||||
// checks if a session user ID is set, and if so grab the user's info
|
||||
exports.userSession = async function(req, res, next) {
|
||||
if ('user' in req.session) {
|
||||
const user = await User.findAll({
|
||||
where: {
|
||||
id: req.session.user,
|
||||
},
|
||||
});
|
||||
|
||||
// pass user info to views
|
||||
res.locals.user = user[0];
|
||||
}
|
||||
|
||||
next();
|
||||
};
|
@ -10,6 +10,7 @@ db.sequelize = sequelize;
|
||||
|
||||
db.items = require('./item.js')(sequelize, Sequelize);
|
||||
db.licenses = require('./license.js')(sequelize, Sequelize);
|
||||
db.users = require('./user.js')(sequelize, Sequelize);
|
||||
|
||||
module.exports = db;
|
||||
|
||||
|
39
src/models/user.js
Normal file
39
src/models/user.js
Normal file
@ -0,0 +1,39 @@
|
||||
module.exports = (sequelize, Sequelize) => {
|
||||
const User = sequelize.define('user', {
|
||||
|
||||
username: {
|
||||
type: Sequelize.STRING,
|
||||
allowNull: false,
|
||||
unique: true,
|
||||
},
|
||||
|
||||
email: {
|
||||
type: Sequelize.STRING,
|
||||
allowNull: false,
|
||||
unique: true,
|
||||
},
|
||||
|
||||
password: {
|
||||
type: Sequelize.STRING,
|
||||
allowNull: false,
|
||||
},
|
||||
|
||||
salt: {
|
||||
type: Sequelize.STRING,
|
||||
allowNull: false,
|
||||
},
|
||||
|
||||
firstName: {
|
||||
type: Sequelize.STRING,
|
||||
allowNull: true,
|
||||
},
|
||||
|
||||
lastName: {
|
||||
type: Sequelize.STRING,
|
||||
allowNull: true,
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
return User;
|
||||
};
|
58
src/routes/auth.js
Normal file
58
src/routes/auth.js
Normal file
@ -0,0 +1,58 @@
|
||||
const db = require('../models');
|
||||
const User = db.users;
|
||||
const crypto = require('crypto');
|
||||
|
||||
// GET - /auth/login
|
||||
exports.getLogin = async function(req, res) {
|
||||
res.render('auth/login.twig');
|
||||
};
|
||||
|
||||
// POST - /auth/login
|
||||
exports.postLogin = async function(req, res) {
|
||||
const user = await User.findAll({
|
||||
where: {
|
||||
username: req.body.login_username,
|
||||
},
|
||||
});
|
||||
|
||||
const attemptedKey = crypto.pbkdf2Sync(req.body.login_password, user[0].salt, 10000, 64, 'sha512');
|
||||
const attemptedHash = attemptedKey.toString('hex');
|
||||
|
||||
if (attemptedHash == user[0].password) {
|
||||
req.session.user = user[0].id;
|
||||
res.redirect('/');
|
||||
} else {
|
||||
res.redirect('/auth/login');
|
||||
}
|
||||
}
|
||||
|
||||
// GET - /auth/register
|
||||
exports.getRegister = async function(req, res) {
|
||||
res.render('auth/register.twig');
|
||||
};
|
||||
|
||||
// POST - /auth/register
|
||||
exports.postRegister = async function(req, res) {
|
||||
const passwordSalt = crypto.randomBytes(32).toString('base64');
|
||||
const passwordKey = crypto.pbkdf2Sync(req.body.register_password, passwordSalt, 10000, 64, 'sha512');
|
||||
const passwordHash = passwordKey.toString('hex');
|
||||
|
||||
const user = await User.create({
|
||||
username: req.body.register_username,
|
||||
password: passwordHash,
|
||||
salt: passwordSalt,
|
||||
email: req.body.register_email,
|
||||
firstName: req.body.register_first_name,
|
||||
lastName: req.body.register_last_name,
|
||||
});
|
||||
|
||||
res.redirect('/');
|
||||
};
|
||||
|
||||
// GET - /auth/logout
|
||||
exports.getLogout = async function(req, res) {
|
||||
// destroy the user's session
|
||||
req.session.destroy();
|
||||
|
||||
res.redirect('/');
|
||||
}
|
40
views/auth/login.twig
Normal file
40
views/auth/login.twig
Normal file
@ -0,0 +1,40 @@
|
||||
{% extends 'layout.twig' %}
|
||||
|
||||
{% block title %}Home{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<!-- page header -->
|
||||
<header class="row">
|
||||
<div class="columns twelve">
|
||||
<h1>Login to your account.</h1>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section id="record-actions" class="row">
|
||||
<div class="three columns">
|
||||
<p>.</p>
|
||||
</div>
|
||||
|
||||
<div class="six columns">
|
||||
<form class="u-full-width" action="/auth/login" method="POST">
|
||||
<div class="row">
|
||||
<label for="login_username">
|
||||
Username:
|
||||
<input type="text" id="login_username" class="u-full-width" name="login_username" placeholder="myuser1">
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="twelve columns">
|
||||
<label for="login_password">
|
||||
Password:
|
||||
<input type="password" id="login_password" class="u-full-width" name="login_password" placeholder="Enter your password...">
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<input type="submit" class="button-primary u-full-width" value="Login">
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{% endblock %}
|
67
views/auth/register.twig
Normal file
67
views/auth/register.twig
Normal file
@ -0,0 +1,67 @@
|
||||
{% extends 'layout.twig' %}
|
||||
|
||||
{% block title %}Home{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<!-- page header -->
|
||||
<header class="row">
|
||||
<div class="columns twelve">
|
||||
<h1>Register for a new account.</h1>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section id="record-actions" class="row">
|
||||
<div class="three columns">
|
||||
<p>.</p>
|
||||
</div>
|
||||
|
||||
<div class="six columns">
|
||||
<form class="u-full-width" action="/auth/register" method="POST">
|
||||
<div class="row">
|
||||
<div class="six columns">
|
||||
<label for="register_username">
|
||||
Username:
|
||||
<input type="text" id="register_username" class="u-full-width" name="register_username" placeholder="myuser1">
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="six columns">
|
||||
<label for="register_password">
|
||||
Password:
|
||||
<input type="password" id="register_password" class="u-full-width" name="register_password" placeholder="Enter your password...">
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="twelve columns">
|
||||
<label for="register_email">
|
||||
Email address:
|
||||
<input type="email" id="register_email" class="u-full-width" name="register_email" placeholder="myemail@example.com">
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="six columns">
|
||||
<label for="register_first_name">
|
||||
First name:
|
||||
<input type="text" id="register_first_name" class="u-full-width" name="register_first_name" placeholder="Firstname">
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="six columns">
|
||||
<label for="register_last_name">
|
||||
Last name:
|
||||
<input type="password" id="register_last_name" class="u-full-width" name="register_last_name" placeholder="Lastname">
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input type="submit" class="button-primary u-full-width" value="Register account">
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{% endblock %}
|
@ -33,6 +33,14 @@
|
||||
|
||||
<button id="search-button" type="submit" for="search-form"><i class="fa-solid fa-magnifying-glass"></i></button>
|
||||
</li>
|
||||
|
||||
{% if user %}
|
||||
<li class="nav-link"><a href="/account">{{ user.username }}</a></li>
|
||||
<li class="nav-link"><a href="/auth/logout">Logout</a></li>
|
||||
{% else %}
|
||||
<li class="nav-link"><a href="/auth/register">Register</a></li>
|
||||
<li class="nav-link"><a href="/auth/login">Login</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
Loading…
Reference in New Issue
Block a user