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> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user