diff --git a/config.example.json b/config.example.json index 069cd09..5da6bc6 100644 --- a/config.example.json +++ b/config.example.json @@ -15,6 +15,6 @@ "url": "mongodb://localhost:27017/pretendo_website" }, "secrets": { - "session": "abcdef" + "session": "session secret here" } } diff --git a/helpers/blog-helper.js b/helpers/blog-helper.js index 25d3e76..1d12366 100644 --- a/helpers/blog-helper.js +++ b/helpers/blog-helper.js @@ -5,13 +5,9 @@ blog post helper functionality */ -//import filesystem +// imports const fs = require('fs'); - -//import author list const authors = require('../config.json').blog.authors; - -//import markdown converter const showdown = require('showdown'); const converter = new showdown.Converter({metadata: true}); @@ -54,7 +50,6 @@ function writeMarkdownToFile(text) { fs.writeFileSync(`posts/${length}.md`, text); } -// export the router module.exports = { getBlogPostAsHtml, getBlogPostAsMarkdown, diff --git a/helpers/common.js b/helpers/common.js index 29aced3..bb96408 100644 --- a/helpers/common.js +++ b/helpers/common.js @@ -5,48 +5,64 @@ common page functionality. */ -function sendDefault404(req, res) { +// shows 404 template. +function sendDefault404(res) { res.status(404).send('404'); } -function sendApi404(req, res) { +// use for any api return. it has basic layout used for every return. +function sendApiReturn(res, data, errors) { + res.status(200).json({ + code: 200, + success: true, + errors: [] + errors + } + data); +} + + +// use if api endpoint doesnt exist +function sendApi404(res) { res.status(404).json({ - error: { - code: 404, - message: 'Endpoint not in use' - } + code: 404, + errors: [ + 'Endpoint not in use' + ] }); } -function sendApiAuthError(req, res) { +// use if not logged in and is required (handled with middleware) +function sendApiAuthError(res) { res.status(401).json({ - error: { - code: 401, - message: 'Not authenticated' - } + code: 401, + errors: [ + 'Not authenticated' + ] }); } -function sendApiGenericError(req, res) { +// use for completely broken requests +function sendApiGenericError(res) { res.status(400).json({ - error: { - code: 400, - message: 'Bad request' - } + code: 400, + success: false, + errors: [ + 'Bad request' + ] }); } -function sendApiError(res, code, message) { +// use for any api not successfull +function sendApiError(res, code, errors) { res.status(code).json({ - error: { - code, - message - } + code, + success: false, + errors }); } module.exports = { sendDefault404, + sendApiReturn, sendApi404, sendApiGenericError, sendApiError, diff --git a/middleware/admin-authentication.js b/middleware/admin-authentication.js index dd27975..e75e649 100644 --- a/middleware/admin-authentication.js +++ b/middleware/admin-authentication.js @@ -1,7 +1,16 @@ +/* + +admin-authentication.js - +Middleware file for authentication checking + +*/ + +// imports const common = require('../helpers/common'); -function authenticationRequired(req, res, next) { - if (req.isAuthenticated()) { +// middleware to use if admin authentication is required +function adminAuthenticationRequired(req, res, next) { + if (req.isAuthenticated() && req.user.role && req.user.role === 'admin') { return next(); } else { console.log('sending auth error'); @@ -9,11 +18,12 @@ function authenticationRequired(req, res, next) { } } +// middleware to use if authentication function authenticationOptional(req, res, next) { return next(); } module.exports = { - authenticationRequired, + adminAuthenticationRequired, authenticationOptional }; \ No newline at end of file diff --git a/models/admin-user.js b/models/admin-user.js index 289034f..bcda1c8 100644 --- a/models/admin-user.js +++ b/models/admin-user.js @@ -5,10 +5,12 @@ file containing the model file for admin user */ +// imports const mongoose = require('mongoose'); const uniqueValidator = require('mongoose-unique-validator'); const bcrypt = require('bcrypt'); +// admin user database layout const adminUserSchema = new mongoose.Schema({ username: { type: String, @@ -16,26 +18,31 @@ const adminUserSchema = new mongoose.Schema({ minlength: [1, 'Username must be at-least 1 character.'], maxlength: [42, 'Username cannot be more than 42 characters long.'], unique: true, - trim: true, + trim: true }, password: { type: String, required: [true, 'Password is required.'], minlength: [7, 'Password must be at-least 7 characters.'], maxlength: [256, 'Password cannot be more than 256 characters long.'], - trim: true, + trim: true + }, + role: { + type: String, + required: true } }); adminUserSchema.plugin(uniqueValidator, {message: '{PATH} already in use.'}); +// hashing password adminUserSchema.pre('save', function(next) { - // only hash the password if it has been modified (or is new) + // only if modified if (!this.isModified('password')) { return next(); } - // Hash the password with 10 rounds. + // hashing bcrypt.hash(this.get('password'), 10, (err, hash) => { if (err) { return next(err); diff --git a/passport.config.js b/passport.config.js index d51f87f..e4fef90 100644 --- a/passport.config.js +++ b/passport.config.js @@ -1,4 +1,11 @@ -// import dependencies +/* + +passport.config.js - +Passport setup file. handles authentication strategy and session setup + +*/ + +// imports const LocalStrategy = require('passport-local').Strategy; const passport = require('passport'); const bcrypt = require('bcrypt'); diff --git a/routes/admin.js b/routes/admin.js index 94b53bd..dfe0467 100644 --- a/routes/admin.js +++ b/routes/admin.js @@ -5,10 +5,8 @@ file for handling admin panel routes */ -// import express' router +// imports const router = require('express').Router(); - -// import dependencies const passport = require('passport'); const common = require('../helpers/common'); const adminUserMiddleware = require('../middleware/admin-authentication'); @@ -57,14 +55,14 @@ router.post('/admin/api/v1/login', passport.authenticate('adminUserStrategy'), f * errors: Strings[messages] * } */ -router.post('/admin/api/v1/register', adminUserMiddleware.authenticationRequired, (req, res) => { - if (!req.body || !req.body.username || !req.body.password) { - // no/wrong post body +router.post('/admin/api/v1/register', adminUserMiddleware.adminAuthenticationRequired, (req, res) => { + if (!req.body) { + // no post body common.sendApiGenericError(req, res); return; } + const { username, password } = req.body; - const newUser = new adminUser.adminUserModel({ username, password @@ -72,12 +70,13 @@ router.post('/admin/api/v1/register', adminUserMiddleware.authenticationRequired newUser.save().then(() => { // successfull - res.status(201).json({ - success: true + common.sendApiReturn(res, { + // TODO return some data + role: req.user.role ? req.user.role : undefined }); return; }).catch((rejection) => { - res.status(500).json(rejection); + common.sendApiError(res, 500, [rejection]); return; }); }); @@ -94,9 +93,9 @@ router.post('/admin/api/v1/register', adminUserMiddleware.authenticationRequired * } */ router.get('/admin/api/v1/check', adminUserMiddleware.authenticationOptional, (req, res) => { - res.status(200).json({ - code: 200, - success: req.isAuthenticated() + common.sendApiReturn(res, { + IsAuthed: req.isAuthenticated(), + role: req.user.role ? req.user.role : undefined }); }); diff --git a/routes/blog.js b/routes/blog.js index f58f2f7..f6dff60 100644 --- a/routes/blog.js +++ b/routes/blog.js @@ -5,7 +5,7 @@ file for handling routes regarding blog posts. */ -// import express' router +// imports const router = require('express').Router(); const blogHelper = require('../helpers/blog-helper.js'); @@ -28,5 +28,5 @@ router.get('/news/:id', async (req, res) => { res.render('post', hbsObject); }); -// export the router +// export router module.exports = router; diff --git a/routes/home.js b/routes/home.js index ca10197..38c9045 100644 --- a/routes/home.js +++ b/routes/home.js @@ -6,7 +6,7 @@ for routes on the root path */ -// import express' router +// imports const router = require('express').Router(); // display home page diff --git a/server.js b/server.js index 1476a98..bc1065d 100644 --- a/server.js +++ b/server.js @@ -1,12 +1,11 @@ /* server.js - -the file that contains the code to run the server +the file that contains the startup code */ -// module imports, and -// some important variable defs +// imports const express = require('express'); const handlebars = require('express-handlebars'); const session = require('express-session'); @@ -14,29 +13,21 @@ const mongoStore = require('connect-mongo')(session); const mongoose = require('mongoose'); const bodyParser = require('body-parser'); const config = require('./config.json'); -const app = express(); const common = require('./helpers/common'); const passportconfig = require('./passport.config.js'); -// import the colors module +// setup console colors require('colors'); -// locations for some files -const locations = { - home: require('./routes/home'), - posts: require('./routes/blog'), - admin: require('./routes/admin') -}; - -// setup body parser -app.use(bodyParser.urlencoded({ extended: false })); // setup database mongoose.connect(config.database.url); const connection = mongoose.connection; connection.on('error', console.error.bind(console, 'connection error:')); -// setup session +// setup express +const app = express(); +app.use(bodyParser.urlencoded({ extended: false })); app.use(session({ secret: config.secrets.session, saveUninitialized: true, @@ -44,48 +35,40 @@ app.use(session({ cookie: { maxAge: 3600000, httpOnly: true//, // remove on production - /*secure: true*/ + /*secure: true*/ // uncomment on production }, - // using store session on MongoDB using express-session + connect + // permanent session storing for MongoDB store: new mongoStore({ mongooseConnection: connection, collection: 'sessions' }) })); - -// setup authentication passportconfig(app); -// load the handlebars module +// handlebars templating setup app.engine('.hbs', handlebars({ extname: '.hbs', layoutsDir: 'views', partialsDir: 'views/partials' })); - -// set express to use handlebars -// as the templating engine app.set('view engine', '.hbs'); -// set some routes on the server +// locations and routes setup +const locations = { + home: require('./routes/home'), + posts: require('./routes/blog'), + admin: require('./routes/admin') +}; -// assets folder serving +// static files app.use('/assets', express.static('assets')); - -// website root +// page map app.use('/', locations.home); - -// blog posts app.use('/', locations.posts); - -// admin panel app.use('/', locations.admin); - -// send a 404 on a file not -// being found app.use(common.sendDefault404); -// start the server +// startup app.listen(config.http.port, () => { console.log(`started the server on port: ${new String(config.http.port).green}`); });