From 56e60df763ed4233286380af6dbab7d2be24a58a Mon Sep 17 00:00:00 2001 From: timakasucces Date: Fri, 25 Jan 2019 04:06:54 +0300 Subject: [PATCH] turned verifyToken to middleware, added description for dbinsert, added hidden csrf field in auth form --- dbinsert.js | 35 ++++++++++++++++++++ package.json | 1 + src/routes/auth.js | 13 +++++--- src/routes/home.js | 5 ++- src/routes/middlewares/token.js | 6 ++-- src/routes/pages.js | 39 +++++++++------------- src/utils/asyncMiddleware.js | 2 +- src/utils/dbinsert.js | 17 ---------- src/views/auth.twig | 1 + yarn.lock | 57 ++++++++++++++++++++++++++++++++- 10 files changed, 125 insertions(+), 51 deletions(-) create mode 100644 dbinsert.js delete mode 100644 src/utils/dbinsert.js diff --git a/dbinsert.js b/dbinsert.js new file mode 100644 index 0000000..be4f3d9 --- /dev/null +++ b/dbinsert.js @@ -0,0 +1,35 @@ +let { password: db } = require('./src/utils/database'); +const md5 = require('md5'); +const program = require('commander'); + +program + .description('Application for inserting new passwords to database.') + .usage('insert [password]') + .command('insert ') + .action(async function (password) { + let doc = { password: md5(password) }; + let newDoc = await db.insert(doc); + + console.log('Password was inserted as', newDoc); + }); + +program.on('--help', () => { + console.log(''); + console.log("Don't forget to update .env file after adding a new password!"); + console.log(''); + console.log('Example:'); + console.log('dbinsert insert qwerty'); + console.log(''); +}); + +program.on('command:*', function () { + console.error('Invalid command: %s\nSee --help for a list of available commands.', program.args.join(' ')); + process.exit(1); +}); + +program.parse(process.argv); + +if (process.argv.length === 2) { + console.error('Invalid command: %s\nSee --help for a list of available commands.', program.args.join(' ')); + process.exit(1); +} diff --git a/package.json b/package.json index 0e27837..9776e7b 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "codex.editor.header": "^2.0.5", "commander": "^2.19.0", "cookie-parser": "~1.4.3", + "csurf": "^1.9.0", "debug": "~4.1.0", "dotenv": "^6.2.0", "express": "~4.16.0", diff --git a/src/routes/auth.js b/src/routes/auth.js index ca15acb..e17073f 100644 --- a/src/routes/auth.js +++ b/src/routes/auth.js @@ -1,17 +1,22 @@ const express = require('express'); const router = express.Router(); +const csrf = require('csurf'); +const bodyParser = require('body-parser'); const { password: db } = require('../utils/database/index'); const jwt = require('jsonwebtoken'); const config = require('../../config/index'); const md5 = require('md5'); +const csrfProtection = csrf({ cookie: true }); +const parseForm = bodyParser.urlencoded({ extended: false }); + /* GET authorization page. */ -router.get('/auth', function (req, res, next) { - res.render('auth', { title: 'Login page ', header: 'Enter password' }); +router.get('/auth', csrfProtection, function (req, res, next) { + res.render('auth', { title: 'Login page ', header: 'Enter password', csrfToken: req.csrfToken() }); }); -router.post('/auth', async (req, res) => { - const passwordDoc = await db.findOne({password: md5(req.body.password)}); +router.post('/auth', parseForm, csrfProtection, async (req, res) => { + const passwordDoc = await db.findOne({ 'password': md5(req.body.password) }); if (passwordDoc !== null) { const token = jwt.sign({ diff --git a/src/routes/home.js b/src/routes/home.js index 05eed38..a80210a 100644 --- a/src/routes/home.js +++ b/src/routes/home.js @@ -3,10 +3,9 @@ const verifyToken = require('./middlewares/token'); const router = express.Router(); /* GET home page. */ -router.get('/', async function (req, res) { - const isAuthorized = await verifyToken(req.cookies.authToken); +router.get('/', verifyToken, async (req, res) => { - res.render('index', { title: 'Express', isAuthorized: isAuthorized }); + res.render('index', { title: 'Express', isAuthorized: req.isAuthorized }); }); module.exports = router; diff --git a/src/routes/middlewares/token.js b/src/routes/middlewares/token.js index 2e53b36..1afbdef 100644 --- a/src/routes/middlewares/token.js +++ b/src/routes/middlewares/token.js @@ -2,7 +2,8 @@ require('dotenv').config(); const config = require('../../../config/index'); const jwt = require('jsonwebtoken'); -module.exports = function verifyToken(token) { +module.exports = async function verifyToken(req, res, next) { + let token = req.cookies.authToken; let isAuthorized = false; jwt.verify(token, process.env.PASSWORD + config.secret, (err, decodedToken) => { @@ -13,5 +14,6 @@ module.exports = function verifyToken(token) { } }); - return isAuthorized; + req.isAuthorized = isAuthorized; + next(); }; diff --git a/src/routes/pages.js b/src/routes/pages.js index 9c64db8..d32a79e 100644 --- a/src/routes/pages.js +++ b/src/routes/pages.js @@ -6,30 +6,26 @@ const verifyToken = require('./middlewares/token'); /** * Create new page form */ -router.get('/page/new', async (req, res) => { - verifyToken(req.cookies.authToken).then( - async () => { - let pagesAvailable = await Pages.getAll(); +router.get('/page/new', verifyToken, async (req, res, next) => { + if (!req.isAuthorized) { + res.render('auth', { title: 'Login page', header: 'Enter password to do this!' }); + } else { + let pagesAvailable = await Pages.getAll(); - res.render('pages/form', { - pagesAvailable, - page: null - }); - }, - () => { - res.render('auth', { title: 'Login page', header: 'Enter password to do this!' }); - } - - ); + res.render('pages/form', { + pagesAvailable, + page: null + }); + } }); /** * Edit page form */ -router.get('/page/edit/:id', async (req, res, next) => { - const isAuthorized = await verifyToken(req.cookies.authToken); - - if (isAuthorized) { +router.get('/page/edit/:id', verifyToken, async (req, res, next) => { + if (!req.isAuthorized) { + res.render('auth', { title: 'Login page', header: 'Enter password to do this!' }); + } else { const pageId = req.params.id; try { @@ -44,17 +40,14 @@ router.get('/page/edit/:id', async (req, res, next) => { res.status(404); next(error); } - } else { - res.render('auth', { title: 'Login page', header: 'Enter password to do this!' }); } }); /** * View page */ -router.get('/page/:id', async (req, res, next) => { +router.get('/page/:id', verifyToken, async (req, res, next) => { const pageId = req.params.id; - let isAuthorized = await verifyToken(req.cookies.authToken); try { let page = await Pages.get(pageId); @@ -62,7 +55,7 @@ router.get('/page/:id', async (req, res, next) => { let pageParent = await page.parent; res.render('pages/page', { - page, pageParent, isAuthorized + page, pageParent, isAuthorized: req.isAuthorized }); } catch (error) { res.status(404); diff --git a/src/utils/asyncMiddleware.js b/src/utils/asyncMiddleware.js index 4bb27ce..6f2278f 100644 --- a/src/utils/asyncMiddleware.js +++ b/src/utils/asyncMiddleware.js @@ -3,7 +3,7 @@ * @param fn * @return {function(*=, *=, *=)} */ -module.exports = function asyncMiddlware(fn) { +module.exports = function asyncMiddleware(fn) { return (req, res, next) => { Promise.resolve(fn(req, res, next)) .catch(next); diff --git a/src/utils/dbinsert.js b/src/utils/dbinsert.js deleted file mode 100644 index 0338282..0000000 --- a/src/utils/dbinsert.js +++ /dev/null @@ -1,17 +0,0 @@ -let { password: db } = require('../utils/database/index'); -const md5 = require('md5'); -const program = require('commander'); - -program - .command('insert ') - .action(async function (value) { - let doc = { password: md5(value) }; - - db.insert(doc); - - let newDoc = await db.findOne({password: md5(value)}); - - console.log('Password was inserted'); - }); - -program.parse(process.argv); diff --git a/src/views/auth.twig b/src/views/auth.twig index cf9e514..251d17f 100644 --- a/src/views/auth.twig +++ b/src/views/auth.twig @@ -3,6 +3,7 @@ {% block body %}

{{header}}

+
diff --git a/yarn.lock b/yarn.lock index 2c9a622..eebdee8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1959,6 +1959,15 @@ crypto-random-string@^1.0.0: resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" integrity sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4= +csrf@~3.0.3: + version "3.0.6" + resolved "https://registry.yarnpkg.com/csrf/-/csrf-3.0.6.tgz#b61120ddceeafc91e76ed5313bb5c0b2667b710a" + integrity sha1-thEg3c7q/JHnbtUxO7XAsmZ7cQo= + dependencies: + rndm "1.2.0" + tsscmp "1.0.5" + uid-safe "2.1.4" + css-color-names@0.0.4, css-color-names@^0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" @@ -2130,6 +2139,16 @@ csso@^3.5.0: dependencies: css-tree "1.0.0-alpha.29" +csurf@^1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/csurf/-/csurf-1.9.0.tgz#49d2c6925ffcec7b7de559597c153fa533364133" + integrity sha1-SdLGkl/87Ht95VlZfBU/pTM2QTM= + dependencies: + cookie "0.3.1" + cookie-signature "1.0.6" + csrf "~3.0.3" + http-errors "~1.5.0" + cyclist@~0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640" @@ -3305,6 +3324,15 @@ http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3: setprototypeof "1.1.0" statuses ">= 1.4.0 < 2" +http-errors@~1.5.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.5.1.tgz#788c0d2c1de2c81b9e6e8c01843b6b97eb920750" + integrity sha1-eIwNLB3iyBuebowBhDtrl+uSB1A= + dependencies: + inherits "2.0.3" + setprototypeof "1.0.2" + statuses ">= 1.3.1 < 2" + http-errors@~1.7.1: version "1.7.1" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.1.tgz#6a4ffe5d35188e1c39f872534690585852e1f027" @@ -5784,6 +5812,11 @@ querystring@0.2.0: resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= +random-bytes@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/random-bytes/-/random-bytes-1.0.0.tgz#4f68a1dc0ae58bd3fb95848c30324db75d64360b" + integrity sha1-T2ih3Arli9P7lYSMMDJNt11kNgs= + randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: version "2.0.6" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.6.tgz#d302c522948588848a8d300c932b44c24231da80" @@ -6120,6 +6153,11 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^3.0.0" inherits "^2.0.1" +rndm@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/rndm/-/rndm-1.2.0.tgz#f33fe9cfb52bbfd520aa18323bc65db110a1b76c" + integrity sha1-8z/pz7Urv9UgqhgyO8ZdsRCht2w= + run-async@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" @@ -6266,6 +6304,11 @@ setimmediate@^1.0.4: resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= +setprototypeof@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.2.tgz#81a552141ec104b88e89ce383103ad5c66564d08" + integrity sha1-gaVSFB7BBLiOic44MQOtXGZWTQg= + setprototypeof@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" @@ -6471,7 +6514,7 @@ static-extend@^0.1.1: define-property "^0.2.5" object-copy "^0.1.0" -"statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2": +"statuses@>= 1.3.1 < 2", "statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2": version "1.5.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= @@ -6833,6 +6876,11 @@ tslib@^1.9.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ== +tsscmp@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/tsscmp/-/tsscmp-1.0.5.tgz#7dc4a33af71581ab4337da91d85ca5427ebd9a97" + integrity sha1-fcSjOvcVgatDN9qR2FylQn69mpc= + tty-browserify@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" @@ -6880,6 +6928,13 @@ uglify-js@^3.1.4: commander "~2.17.1" source-map "~0.6.1" +uid-safe@2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/uid-safe/-/uid-safe-2.1.4.tgz#3ad6f38368c6d4c8c75ec17623fb79aa1d071d81" + integrity sha1-Otbzg2jG1MjHXsF2I/t5qh0HHYE= + dependencies: + random-bytes "~1.0.0" + undefsafe@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.2.tgz#225f6b9e0337663e0d8e7cfd686fc2836ccace76"