summaryrefslogtreecommitdiffstats
path: root/server/lib/authentication.js
diff options
context:
space:
mode:
authorJannik Schönartz2019-02-26 08:18:52 +0100
committerJannik Schönartz2019-02-26 08:18:52 +0100
commitdcd82e1c5847151678ae7ffc982b4595304c1eeb (patch)
treed3a7ea5a6390e0c1c2bb49ef24f31b1ddec50606 /server/lib/authentication.js
parent[webapp/configurator] disable touch swipe tabs switching (diff)
downloadbas-dcd82e1c5847151678ae7ffc982b4595304c1eeb.tar.gz
bas-dcd82e1c5847151678ae7ffc982b4595304c1eeb.tar.xz
bas-dcd82e1c5847151678ae7ffc982b4595304c1eeb.zip
[authentication] Rewrite code in async/await, fix edit account module
Diffstat (limited to 'server/lib/authentication.js')
-rw-r--r--server/lib/authentication.js143
1 files changed, 77 insertions, 66 deletions
diff --git a/server/lib/authentication.js b/server/lib/authentication.js
index 9a91850..dcbe880 100644
--- a/server/lib/authentication.js
+++ b/server/lib/authentication.js
@@ -6,31 +6,34 @@ var db = require(path.join(__appdir, 'lib', 'sequelize'))
var securePassword = require('secure-password')
var pwd = securePassword()
-module.exports = { loginCookie, loginToken, logout, verifyToken, signup, changePassword, validateEmail }
+module.exports = { loginCookie, loginToken, logout, verifyToken, signup, changePassword, validateEmail, validateUsername }
// Authentifivation method for the frontend using secure httpOnly cookies. (POST)
-function loginCookie (req, res) {
+async function loginCookie (req, res) {
var params = req.body
- verifyUser(res, params.username, params.password, token => {
- // The token has the form header.payload.signature
- // We split the cookie in header.payload and signature in two seperate cookies.
- // The signature cookie is httpOnly so JavaScript never has access to the full cookie.
- // Read more at: https://medium.com/lightrail/getting-token-authentication-right-in-a-stateless-single-page-application-57d0c6474e3
- const split = token.split('.')
- const headerPayload = split[0] + '.' + split[1]
- const signature = split[2]
- res.cookie('jwt_hp', headerPayload, { secure: true, httpOnly: false, sameSite: 'strict' })
- res.cookie('jwt_s', signature, { secure: true, httpOnly: true, sameSite: 'strict' })
- return res.status(200).send({ auth: true, status: 'VALID' })
- })
+ var result = await verifyUser(res, params.username, params.password)
+ if (result.status !== 'SUCCESS') return res.status(401).send(result)
+
+ // The token has the form header.payload.signature
+ // We split the cookie in header.payload and signature in two seperate cookies.
+ // The signature cookie is httpOnly so JavaScript never has access to the full cookie.
+ // Read more at: https://medium.com/lightrail/getting-token-authentication-right-in-a-stateless-single-page-application-57d0c6474e3
+ const split = result.data.token.split('.')
+ const headerPayload = split[0] + '.' + split[1]
+ const signature = split[2]
+ res.cookie('jwt_hp', headerPayload, { secure: true, httpOnly: false, sameSite: 'strict' })
+ res.cookie('jwt_s', signature, { secure: true, httpOnly: true, sameSite: 'strict' })
+ return res.status(200).send({ auth: true, status: 'VALID' })
}
// Authentification method for the API using the authorization header. (GET)
-function loginToken (req, res) {
+async function loginToken (req, res) {
var body = req.body
- verifyUser(res, body.username, body.password, function (token) {
- return res.status(200).send({ auth: true, token })
- })
+
+ var result = await verifyUser(res, body.username, body.password)
+ if (result.status !== 'SUCCESS') return res.status(401).send(result)
+ const token = result.data.token
+ return res.status(200).send({ auth: true, token })
}
// Method for creating a new user.
@@ -67,8 +70,10 @@ async function signup (req, res) {
var userId = newUser.id
// Verify & improving the hash.
- await verifyHash(res, userPassword, hash, userId, () => {})
- return res.status(200).send({ auth: true, status: 'VALID' })
+ var result = await verifyHash(res, userPassword, hash, userId)
+ if (result.status !== 'SUCCESS') return res.status(401).send(result)
+
+ return newUser
}
// Logout method for the frontend. Deleting the cookies by overwriting them.
@@ -94,11 +99,12 @@ async function changePassword (req, res) {
if (req.body.passwordCurrent) {
// Verify the current hast with the provided current password.
const pwCurrent = Buffer.from(req.body.passwordCurrent)
- await verifyHash(res, pwCurrent, Buffer.from(user.password), user.id)
+ var result = await verifyHash(res, pwCurrent, Buffer.from(user.password), user.id)
+ if (result.status !== 'SUCCESS') return res.status(400).send(result)
}
// 3. Check if the new provided password fullfills the requirements
- if (!validatePassword(req.body.password)) return res.send({ status: 'PASSWORD_REQUIREMENTS', error_message: 'The provided password doesn\'t fullfill the requirements' })
+ if (!validatePassword(req.body.password)) return res.status(400).send({ status: 'PASSWORD_REQUIREMENTS', error_message: 'The provided password doesn\'t fullfill the requirements' })
// 4. Calculate the new password hash.
try {
@@ -168,60 +174,65 @@ function validateEmail (email) {
// ############## Helper function #################
// ################################################
-// The function for verifying a user. Callback only gets called if the user gets verified.
-function verifyUser (res, username, password, callback) {
- if (!username) return res.status(401).send({ auth: false, status: 'USER_MISSING', error_message: 'This service requires an username.' })
- if (!password) return res.status(401).send({ auth: false, status: 'PASSWORD_MISSING', error_message: 'This services requires a password.' })
+// The function for verifying a user.
+async function verifyUser (res, username, password) {
+ if (!username) return { auth: false, status: 'USER_MISSING', error_message: 'This service requires an username.' }
+ if (!password) return { auth: false, status: 'PASSWORD_MISSING', error_message: 'This services requires a password.' }
- db.user.findOne({ where: { username: username } }).then(userDb => {
- if (!userDb) {
- return res.status(401).send({ auth: false, status: 'USER_NOTFOUND', error_message: 'User does not exist.' })
- }
- var user = {}
- user.id = userDb.id
- var userPassword = Buffer.from(password)
- var hash = Buffer.from(userDb.password)
-
- // Verify & improving the hash.
- verifyHash(res, userPassword, hash, user.id, () => {
- jwt.sign({ user }, config.secret, { expiresIn: '12h' }, (err, token) => {
- if (err) return res.status(401).send({ auth: false, status: 'JWT_ERROR', error_message: 'Jwt sign failed.' })
- return callback(token)
- })
- })
- })
+ const userDb = await db.user.findOne({ where: { username: username } })
+ if (!userDb) {
+ return { auth: false, status: 'USER_NOTFOUND', error_message: 'User does not exist.' }
+ }
+ var user = {}
+ user.id = userDb.id
+ var userPassword = Buffer.from(password)
+ var hash = Buffer.from(userDb.password)
+
+ // Verify & improving the hash.
+ var result = await verifyHash(res, userPassword, hash, user.id)
+ if (result.status !== 'SUCCESS') return result
+
+ try {
+ var token = await jwt.sign({ user }, config.secret, { expiresIn: '12h' })
+ } catch (error) {
+ return { auth: false, status: 'JWT_ERROR', error_message: 'Jwt sign failed.' }
+ }
+
+ return { auth: true, status: 'SUCCESS', data: { token: token } }
}
// The verify hash function from the secure-passwords with error handling.
-function verifyHash (res, password, hash, userId, callback = () => {}) {
+async function verifyHash (res, password, hash, userId) {
// Check if the hash in the database fullfills the requirements needed for pwd.verify.
// Hash will be a Buffer of length SecurePassword.HASH_BYTES.
- if (hash.length !== securePassword.HASH_BYTES) return res.status(401).send({ auth: false, status: 'DATABASE_HASH_INVALID', error_message: 'The hash in the database is corrupted.' })
+ if (hash.length !== securePassword.HASH_BYTES) return { auth: false, status: 'DATABASE_HASH_INVALID', error_message: 'The hash in the database is corrupted.' }
// Password must be a Buffer of length SecurePassword.PASSWORD_BYTES_MIN - SecurePassword.PASSWORD_BYTES_MAX.
- if (password.length < securePassword.PASSWORD_BYTES_MIN || password.length > securePassword.PASSWORD_BYTES_MAX) return res.status(401).send({ auth: false, status: 'PASSWORD_INVALID', error_message: 'The provided password has an invalid length.' })
+ if (password.length < securePassword.PASSWORD_BYTES_MIN || password.length > securePassword.PASSWORD_BYTES_MAX) return { auth: false, status: 'PASSWORD_INVALID', error_message: 'The provided password has an invalid length.' }
// Verification of the password. Rehash if needed.
- pwd.verify(password, hash, function (err, result) {
- if (err) return res.status(401).send({ auth: false, status: 'PASSWORD_VERIFY_ERROR', error_message: 'Verifying the password failed.' })
-
- // Check the state of the verification.
- if (result === securePassword.INVALID_UNRECOGNIZED_HASH) return res.status(401).send({ auth: false, status: 'INVALID_UNRECOGNIZED_HASH', error_message: 'This hash was not made with secure-password. Attempt legacy algorithm.' })
- if (result === securePassword.INVALID) return res.status(401).send({ auth: false, status: 'PASSWORD_INVALID', error_message: 'The provided password is invalid.' })
- if (result === securePassword.VALID) callback()
- if (result === securePassword.VALID_NEEDS_REHASH) {
- pwd.hash(password, function (err, improvedHash) {
- if (err) throw err
-
- // Update the improved hash in the db.
- db.user.findOne({ where: { id: userId } }).then(user => {
- user.updateAttributes({
- password: improvedHash
- })
- return callback()
- })
- })
+ try {
+ var result = await pwd.verify(password, hash)
+ } catch (error) {
+ return { auth: false, status: 'PASSWORD_VERIFY_ERROR', error_message: 'Verifying the password failed.' }
+ }
+
+ // Check the state of the verification.
+ if (result === securePassword.INVALID_UNRECOGNIZED_HASH) return { auth: false, status: 'INVALID_UNRECOGNIZED_HASH', error_message: 'This hash was not made with secure-password. Attempt legacy algorithm.' }
+ if (result === securePassword.INVALID) return { auth: false, status: 'PASSWORD_INVALID', error_message: 'The provided password is invalid.' }
+ if (result === securePassword.VALID) return { status: 'SUCCESS' }
+ if (result === securePassword.VALID_NEEDS_REHASH) {
+ try {
+ var improvedHash = await pwd.hash(password)
+ } catch (error) {
+ return { auth: false, status: 'PASSWORD_REHASH_ERROR', error_message: 'Rehashing the password failed.' }
}
- })
+ // Update the improved hash in the db.
+ const user = await db.user.findOne({ where: { id: userId } })
+ await user.updateAttributes({
+ password: improvedHash
+ })
+ return { status: 'SUCCESS' }
+ }
}
// Function for validating the password. Password requirements are implemented here.