From acf084743df3e868af0f4733f0db38818e93216c Mon Sep 17 00:00:00 2001 From: AdamSBlack Date: Sun, 3 Oct 2021 17:44:43 +0100 Subject: [PATCH] updated database, sessions managed via signed JWT token. TODO: sign tokens based user unique token, instead of global salt key --- controllers/authentication.js | 64 +++++++++++++++++++++++++--------- database.empty.sqlite | Bin 28672 -> 28672 bytes routes/useradmin.js | 23 ++++++------ 3 files changed, 58 insertions(+), 29 deletions(-) diff --git a/controllers/authentication.js b/controllers/authentication.js index a83bc37..2bcd2a3 100644 --- a/controllers/authentication.js +++ b/controllers/authentication.js @@ -23,6 +23,27 @@ async function readJWT(token) { return null; } +async function signIn(email, password) { + + let account = await models_orm.models.accounts.findOne({where: {email: email}}); + + + if (account.dataValues) { + account = account.dataValues; + + const inputPassword = crypto.createHash('sha256').update(password + config.applicationSalt).digest('hex'); + + if (account.password === inputPassword) { + const token = jwt.sign({accountId: account.id}, config.applicationSalt) + return {success: true, jwt: token}; + } else { + return {success: false, msg: 'BAD PASSWORD', invalidPassword: true} + } + } else { + return {success: false, msg: 'BAD ACCOUNT', badAccount: true} + } +} + async function changePassword(account, newPassword, oldPassword) { if (!account || !newPassword || !oldPassword) { return {success: false, error: 'MISSING_DATA'}} @@ -42,29 +63,37 @@ async function changePassword(account, newPassword, oldPassword) { } } +/* + TODO: update rest of the code to support authentication rejection reasons +*/ + async function getAuthenticatedAccount(req, res) { - const sessionCookie = (req.signedCookies !== undefined ? req.signedCookies.session : null); - if (!sessionCookie || sessionCookie.expires <= Date.now()) { return null; } - const email = sessionCookie.account.trim().toLowerCase(); + const sessionJWT = (req.signedCookies !== undefined ? req.signedCookies.jwt : null) + if ((!sessionJWT || sessionJWT.expires <= Date.now())) { return null; } + const token = jwt.verify(sessionJWT, config.applicationSalt); - // TODO stop storing emails in the cookie - const account = await models_orm.models.accounts.findOne({where: {email: email}}); + if (token && token.accountId) { + const account = await models_orm.models.accounts.findOne({where: {id: token.accountId}}); - if (account.dataValues) { - const update = models_orm.models.accounts.update({ last_ping: Date.now() }, - { where: { id: account.id } } - ) + if (account.dataValues) { + const update = models_orm.models.accounts.update({ last_ping: Date.now() }, + { where: { id: account.id } } + ) - - if (!account || account.banned) { - res ? res.clearCookie('session') : logger.warn(`getAuthenticatedAccount unable to clear banned user (${account.email}) cookie, res not passed`); - return false + if (!account || account.banned) { + return null; // {success: false, isBanned: true} + } + return account; + } else { + return null; // {success: false, isInvalid: true} } - return account; } else { - res ? res.clearCookie('session') : logger.warn(`getAuthenticatedAccount unable to clear banned user (${account.email}) cookie, res not passed`); - return false; + return null; // {success: false, badToken: true} } + + return null; + + } @@ -75,6 +104,7 @@ module.exports = (_models, _logger) => { return { validateJWT: validateJWT, getAuthenticatedAccount: getAuthenticatedAccount, - changePassword: changePassword + changePassword: changePassword, + signIn: signIn } } diff --git a/database.empty.sqlite b/database.empty.sqlite index 4a4b60108e2d740c0bc2b850f0700a3544c7caf6..bd91dd897e11684fbc36652ace8a6b236c6559d9 100644 GIT binary patch delta 193 zcmZp8z}WDBae}nqI|c>@b|_{9(h(DNj3wVO=y^}%<(6b%<&0wByTBR6eV#XqCxOFs zv!Fm6`{Zlv;X>S!jJo3b`iwwY6+|}|Pkz8IIysBuuCP*ZYH@L9eqMZWYHErSXNYS= z$YvML7A8jS$tSs^8SN)FDylRoaE^_e#H5_m;=-IJcA$u?EMs%xaz-)mUEqx3KF^!QQ^w)F zSx_L3eeyN-@X3pL<+!*d8TrNa^%!F#rGn diff --git a/routes/useradmin.js b/routes/useradmin.js index e33383e..44f3963 100644 --- a/routes/useradmin.js +++ b/routes/useradmin.js @@ -24,21 +24,23 @@ let logger; router.post('/useradmin/auth', bodyParser.urlencoded({extended: true}), runAsyncWrapper(async (req, res) => { - const account = await models.__db.get('SELECT * FROM accounts WHERE email = ? AND password = ?', req.body.email, crypto.createHash('sha256').update(req.body.password + config.applicationSalt).digest('hex')); + const signIn = await controllers.authentication.signIn(req.body.email, req.body.password) - if (!account || account.banned) { - res.status(200); + console.log(signIn) + + if (signIn.success) { + res.cookie('jwt', signIn.jwt, {signed: true}); + res.redirect('/useradmin/overview'); + } else { res.redirect('/useradmin?status=' + encodeURIComponent('Invalid credentials or banned account')); - return; } - res.cookie('session', {account: account.email, expires: Date.now() + 1000 * 3600 * 24 * 365}, {signed: true}); - res.redirect('/useradmin/overview'); })) router.get('/useradmin/signout', runAsyncWrapper(async (req, res) => { res.clearCookie('session'); - res.redirect('/useradmin'); + res.clearCookie('jwt'); + res.redirect('/useradmin?status=' + encodeURIComponent('Signed out')); })) @@ -124,11 +126,8 @@ router.post('/useradmin/register/token', bodyParser.urlencoded({extended: true}) if (result.lastID != undefined) { logger.info("USERADMIN REGISTRATION - created new account #" + result.lastID + " with email " + email + ""); - res.cookie('session', { - account: email, - expires: Date.now() + 1000 * 3600 * 24 * 365 - }, {signed: true}); - res.redirect('/useradmin/overview'); + + res.redirect('/useradmin?status=' + encodeURIComponent('Successfully registered')); return; } else { logger.error("USERADMIN REGISTRATION - account creation failed, resulting account data for email " + email + " is: " + result);