Compare commits
1 Commits
main
...
11-add-use
Author | SHA1 | Date | |
---|---|---|---|
9a13319948 |
@ -19,6 +19,12 @@ a{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
header{
|
||||||
|
h1{
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.button.button-primary,
|
.button.button-primary,
|
||||||
button.button-primary,
|
button.button-primary,
|
||||||
input[type="button"].button-primary,
|
input[type="button"].button-primary,
|
||||||
@ -56,6 +62,7 @@ input[type="submit"].button-primary{
|
|||||||
}
|
}
|
||||||
.nav-bar-right{
|
.nav-bar-right{
|
||||||
float: right;
|
float: right;
|
||||||
|
margin-right: 35px;
|
||||||
}
|
}
|
||||||
|
|
||||||
ul{
|
ul{
|
||||||
|
10
index.js
10
index.js
@ -42,6 +42,10 @@ app.use(express.urlencoded({
|
|||||||
extended: true,
|
extended: true,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// load middleware
|
||||||
|
const userSessionMiddleware = require('./src/middleware/user-session');
|
||||||
|
app.use(userSessionMiddleware.userSession);
|
||||||
|
|
||||||
// load the template engine
|
// load the template engine
|
||||||
app.set('view engine', 'twig');
|
app.set('view engine', 'twig');
|
||||||
|
|
||||||
@ -50,12 +54,18 @@ app.use(express.static('public'));
|
|||||||
|
|
||||||
// load route handlers
|
// load route handlers
|
||||||
const homeRoutes = require('./src/routes/home');
|
const homeRoutes = require('./src/routes/home');
|
||||||
|
const authRoutes = require('./src/routes/auth');
|
||||||
const itemRoutes = require('./src/routes/item');
|
const itemRoutes = require('./src/routes/item');
|
||||||
const licenseRoutes = require('./src/routes/license');
|
const licenseRoutes = require('./src/routes/license');
|
||||||
const searchRoutes = require('./src/routes/search');
|
const searchRoutes = require('./src/routes/search');
|
||||||
|
|
||||||
// register route handlers
|
// register route handlers
|
||||||
app.get('/', homeRoutes.getIndex);
|
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.get('/item/add', itemRoutes.getAdd);
|
||||||
app.post('/item/add', itemRoutes.postAdd);
|
app.post('/item/add', itemRoutes.postAdd);
|
||||||
app.get('/item/:id', itemRoutes.getItem);
|
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.items = require('./item.js')(sequelize, Sequelize);
|
||||||
db.licenses = require('./license.js')(sequelize, Sequelize);
|
db.licenses = require('./license.js')(sequelize, Sequelize);
|
||||||
|
db.users = require('./user.js')(sequelize, Sequelize);
|
||||||
|
|
||||||
module.exports = db;
|
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>
|
<button id="search-button" type="submit" for="search-form"><i class="fa-solid fa-magnifying-glass"></i></button>
|
||||||
</li>
|
</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>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
Loading…
Reference in New Issue
Block a user