summaryrefslogtreecommitdiffstats
path: root/server/lib/authentication.js
diff options
context:
space:
mode:
authorJannik Schönartz2018-07-17 04:43:31 +0200
committerJannik Schönartz2018-07-17 04:43:31 +0200
commite4c4d0e3d7dc7be7ac233cd6c9b90ae92fb1a5b3 (patch)
tree0c40021f77fea9688449c9c4d6e6222a809ec3d6 /server/lib/authentication.js
parent[webapp] renamed components (diff)
downloadbas-e4c4d0e3d7dc7be7ac233cd6c9b90ae92fb1a5b3.tar.gz
bas-e4c4d0e3d7dc7be7ac233cd6c9b90ae92fb1a5b3.tar.xz
bas-e4c4d0e3d7dc7be7ac233cd6c9b90ae92fb1a5b3.zip
[server] Fixed eslint errors. (Standard ESLint is used)
Diffstat (limited to 'server/lib/authentication.js')
-rw-r--r--server/lib/authentication.js366
1 files changed, 178 insertions, 188 deletions
diff --git a/server/lib/authentication.js b/server/lib/authentication.js
index 3a4dccd..b8ee506 100644
--- a/server/lib/authentication.js
+++ b/server/lib/authentication.js
@@ -1,203 +1,193 @@
/* global __appdir */
-var jwt = require('jsonwebtoken');
-var path = require('path');
-var config = require(path.join(__appdir, 'config', 'authentication'));
-//var db = require(path.join(__appdir, 'lib', 'database')).connectionPool;
-var db = require(path.join(__appdir, 'lib', 'sequelize'));
-var securePassword = require('secure-password');
-var pwd = securePassword();
+var jwt = require('jsonwebtoken')
+var path = require('path')
+var config = require(path.join(__appdir, 'config', 'authentication'))
+// var db = require(path.join(__appdir, 'lib', 'database')).connectionPool;
+var db = require(path.join(__appdir, 'lib', 'sequelize'))
+var securePassword = require('secure-password')
+var pwd = securePassword()
module.exports = {
- // Authentifivation method for the frontend using secure httpOnly cookies. (POST)
- login: function(req, res) {
- var params = req.body;
-
- verifyUser(res, params.username, params.password, function(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' });
- });
- },
-
- // Authentification method for the API using the authorization header. (GET)
- auth: function(req, res) {
- var query = req.query;
-
- verifyUser(res, query.username, query.password, function(token) {
- return res.status(200).send({ auth: true, token });
- });
- },
-
- signup: function(req, res) {
- // TODO: Implement some security stuff. Not every user who call this request should be able to sign up.
-
- var params = req.body;
-
- if (!params.username) return res.status(500).send({ auth: false, status: 'USER_MISSING', error_message: 'This service requires an username.' });
- if (!params.password) return res.status(500).send({ auth: false, status: 'PASSWORD_MISSING', error_message: 'This services requires a password.' });
- if (!params.email) return res.status(500).send({ auth: false, status: 'EMAIL_MISSING', error_message: 'This services requires an email.' });
-
- // Database and user validation.
- //SEQ//db.query('SELECT * FROM users WHERE username = ?', [params.username], function(err, rows) {
- db.user.findOne({ where: { username: params.username } }).then(user_db => {
- //SEQ//if (err) return res.status(500).send({ auth: false, status: 'DATABASE_ERROR', error_message: 'SQL query failed.' });
-
- // User exists validation.
- //SEQ//if (rows.length) return res.status(500).send({ auth: false, status: 'USER_ALREADY_EXISTS', error_message: 'The provided username already exists.' });
- if (user_db) return res.status(500).send({ auth: false, status: 'USER_ALREADY_EXISTS', error_message: 'The provided username already exists.' });
-
- // Password requirements validation.
- if (!validatePassword(params.password)) return res.status(500).send({ auth: false, status: 'PASSWORD_REQUIREMENTS', error_message: 'The password requirements are not fullfilled.' });
-
- // Email validation.
- if (!validateEmail(params.email)) return res.status(500).send({ auth: false, status: 'EMAIL_INVALID', error_message: 'The provided email is invalid.' });
-
- var userPassword = Buffer.from(params.password);
-
- // Register user
- pwd.hash(userPassword, function(err, hash) {
- if (err) return res.status(500).send({ auth: false, status: 'PASSWORD_HASH_ERROR', error_message: 'Hashing the password failed.' });
-
- // Saving the non improved hash and creating the user in the db.
- //SEQ//var att = [params.username, hash, params.email, params.name];
- //SEQ//db.query('INSERT INTO users (username, password, email, name) VALUES (?)', [att], function(err, result) {
- db.user.create({ username: params.username, password: hash, email: params.email, name: params.name }).then((user_db) => {
- //SEQ//if (err) return res.status(500).send({ auth: false, status: 'DATABASE_INSERT_ERROR', error_message: 'Inserting the user in the database failed.' });
- // TODO: Username could also be used because those are unique as well.
- //SEQ//var userId = result.insertId;
- var userId = user_db.id;
-
- // Verify & improving the hash.
- verifyHash(res, userPassword, hash, userId, function() {
- return res.status(200).send({ auth: true, status: 'VALID'});
- });
- });
- });
- });
- },
-
- // Logout method for the frontend. Deleting the cookies by overwriting them.
- logout: function(req, res) {
- // End session properly.
-
- res.clearCookie('jwt_hp');
- res.clearCookie('jwt_s');
- return res.status(200).send();
-
- // TODO: Implement.. blacklisting for jwt's and destroy the cookies..
- // Maybe use express-jwt and use the rewoke function.
- },
-
- changePassword: function(req, res) {
- // TODO: IMPLEMENT
- },
-
- verifyToken: function(req, res, next) {
- var token = '';
- // Check for the token in the authorization header or in the cookies. Else return with auth: false.
- if (req.headers['authorization']) {
- var authorization = req.headers['authorization'];
- // Authorization: Bearer <token>
- // Split the bearer token.
- const bearer = authorization.split(' ');
- token = bearer[1];
- } else if (req.cookies.jwt_hp && req.cookies.jwt_s) {
- token = req.cookies.jwt_hp + '.' + req.cookies.jwt_s;
- } else {
- return res.status(403).send({ auth: false, status: 'TOKEN_MISSING', error_message: 'This service requires a token.' });
- }
- // Verify the token with the secret.
- jwt.verify(token, config.secret, function(err) {
- if (err) return res.status(500).send({ auth: false, status: 'TOKEN_INVALID', error_message: 'The provided token is invalid.' });
- req.token = token;
- next();
- });
+ // Authentifivation method for the frontend using secure httpOnly cookies. (POST)
+ login: function (req, res) {
+ var params = req.body
+
+ verifyUser(res, params.username, params.password, function (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' })
+ })
+ },
+ // Authentification method for the API using the authorization header. (GET)
+ auth: function (req, res) {
+ var query = req.query
+
+ verifyUser(res, query.username, query.password, function (token) {
+ return res.status(200).send({ auth: true, token })
+ })
+ },
+
+ signup: function (req, res) {
+ // TODO: Implement some security stuff. Not every user who call this request should be able to sign up.
+
+ var params = req.body
+ if (!params.username) return res.status(500).send({ auth: false, status: 'USER_MISSING', error_message: 'This service requires an username.' })
+ if (!params.password) return res.status(500).send({ auth: false, status: 'PASSWORD_MISSING', error_message: 'This services requires a password.' })
+ if (!params.email) return res.status(500).send({ auth: false, status: 'EMAIL_MISSING', error_message: 'This services requires an email.' })
+ // Database and user validation.
+ // SEQ//db.query('SELECT * FROM users WHERE username = ?', [params.username], function (err, rows) {
+ db.user.findOne({ where: { username: params.username } }).then(userDb => {
+ // SEQ//if (err) return res.status(500).send({ auth: false, status: 'DATABASE_ERROR', error_message: 'SQL query failed.' });
+ // User exists validation.
+ // SEQ//if (rows.length) return res.status(500).send({ auth: false, status: 'USER_ALREADY_EXISTS', error_message: 'The provided username already exists.' });
+ if (userDb) return res.status(500).send({ auth: false, status: 'USER_ALREADY_EXISTS', error_message: 'The provided username already exists.' })
+
+ // Password requirements validation.
+ if (!validatePassword(params.password)) return res.status(500).send({ auth: false, status: 'PASSWORD_REQUIREMENTS', error_message: 'The password requirements are not fullfilled.' })
+ // Email validation.
+ if (!validateEmail(params.email)) return res.status(500).send({ auth: false, status: 'EMAIL_INVALID', error_message: 'The provided email is invalid.' })
+ var userPassword = Buffer.from(params.password)
+ // Register user
+ pwd.hash(userPassword, function (err, hash) {
+ if (err) return res.status(500).send({ auth: false, status: 'PASSWORD_HASH_ERROR', error_message: 'Hashing the password failed.' })
+ // Saving the non improved hash and creating the user in the db.
+ // SEQ//var att = [params.username, hash, params.email, params.name];
+ // SEQ//db.query('INSERT INTO users (username, password, email, name) VALUES (?)', [att], function (err, result) {
+ db.user.create({ username: params.username, password: hash, email: params.email, name: params.name }).then((userDb) => {
+ // SEQ//if (err) return res.status(500).send({ auth: false, status: 'DATABASE_INSERT_ERROR', error_message: 'Inserting the user in the database failed.' });
+ // TODO: Username could also be used because those are unique as well.
+ // SEQ//var userId = result.insertId;
+ var userId = userDb.id
+
+ // Verify & improving the hash.
+ verifyHash(res, userPassword, hash, userId, function () {
+ return res.status(200).send({ auth: true, status: 'VALID' })
+ })
+ })
+ })
+ })
+ },
+
+ // Logout method for the frontend. Deleting the cookies by overwriting them.
+ logout: function (req, res) {
+ // End session properly.
+ res.clearCookie('jwt_hp')
+ res.clearCookie('jwt_s')
+ return res.status(200).send()
+ // TODO: Implement.. blacklisting for jwt's and destroy the cookies..
+ // Maybe use express-jwt and use the rewoke function.
+ },
+
+ changePassword: function (req, res) {
+ // TODO: IMPLEMENT
+ },
+ verifyToken: function (req, res, next) {
+ var token = ''
+ // Check for the token in the authorization header or in the cookies. Else return with auth: false.
+ if (req.headers['authorization']) {
+ var authorization = req.headers['authorization']
+ // Authorization: Bearer <token>
+ // Split the bearer token.
+ const bearer = authorization.split(' ')
+ token = bearer[1]
+ } else if (req.cookies.jwt_hp && req.cookies.jwt_s) {
+ token = req.cookies.jwt_hp + '.' + req.cookies.jwt_s
+ } else {
+ return res.status(403).send({ auth: false, status: 'TOKEN_MISSING', error_message: 'This service requires a token.' })
}
-};
+ // Verify the token with the secret.
+ jwt.verify(token, config.secret, function (err) {
+ if (err) return res.status(500).send({ auth: false, status: 'TOKEN_INVALID', error_message: 'The provided token is invalid.' })
+ req.token = token
+ next()
+ })
+ }
+}
// 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(500).send({ auth: false, status: 'USER_MISSING', error_message: 'This service requires an username.' });
- if (!password) return res.status(500).send({ auth: false, status: 'PASSWORD_MISSING', error_message: 'This services requires a password.' });
-
- //SEQ//db.query('SELECT * FROM users WHERE username = ?', [username], function(err, rows) {
- db.user.findOne({ where: { username: username } }).then(user_db => {
- //SEQ//if (err) return res.status(500).send({ auth: false, status: 'DATABASE_ERROR', error_message: 'Database connection failed.' });
- //SEQ//if (rows.length != 1) {
- //SEQ// return res.status(404).send({ auth: false, status: 'USER_NOTFOUND', error_message: 'User does not exist.' });
- //SEQ//}
-
- if (!user_db) {
- return res.status(404).send({ auth: false, status: 'USER_NOTFOUND', error_message: 'User does not exist.' });
- }
- var user = {};
- //SEQ//user.id = rows[0].id;
- user.id = user_db.id;
- //user.username = rows[0].username;
- //user.email = rows[0].email;
- var userPassword = Buffer.from(password);
- //SEQ//var hash = Buffer.from(rows[0].password);
- var hash = Buffer.from(user_db.password);
-
- // Verify & improving the hash.
- verifyHash(res, userPassword, hash, user.id, function() {
- jwt.sign({user}, config.secret, { expiresIn: '12h' }, (err, token) => {
- if (err) return res.status(500).send({ auth: false, status: 'JWT_ERROR', error_message: 'Jwt sign failed.' });
- return callback(token);
- });
- });
- });
+function verifyUser (res, username, password, callback) {
+ if (!username) return res.status(500).send({ auth: false, status: 'USER_MISSING', error_message: 'This service requires an username.' })
+ if (!password) return res.status(500).send({ auth: false, status: 'PASSWORD_MISSING', error_message: 'This services requires a password.' })
+
+ // SEQ//db.query('SELECT * FROM users WHERE username = ?', [username], function (err, rows) {
+ db.user.findOne({ where: { username: username } }).then(userDb => {
+ // SEQ//if (err) return res.status(500).send({ auth: false, status: 'DATABASE_ERROR', error_message: 'Database connection failed.' });
+ // SEQ//if (rows.length != 1) {
+ // SEQ// return res.status(404).send({ auth: false, status: 'USER_NOTFOUND', error_message: 'User does not exist.' });
+ // SEQ//}
+ if (!userDb) {
+ return res.status(404).send({ auth: false, status: 'USER_NOTFOUND', error_message: 'User does not exist.' })
+ }
+ var user = {}
+ // SEQ//user.id = rows[0].id;
+ user.id = userDb.id
+ // user.username = rows[0].username;
+ // user.email = rows[0].email;
+ var userPassword = Buffer.from(password)
+ // SEQ//var hash = Buffer.from(rows[0].password);
+ var hash = Buffer.from(userDb.password)
+
+ // Verify & improving the hash.
+ verifyHash(res, userPassword, hash, user.id, function () {
+ jwt.sign({user}, config.secret, { expiresIn: '12h' }, (err, token) => {
+ if (err) return res.status(500).send({ auth: false, status: 'JWT_ERROR', error_message: 'Jwt sign failed.' })
+ return callback(token)
+ })
+ })
+ })
}
// The verify hash function from the secure-passwords with error handling.
-function verifyHash(res, password, hash, userId, callback) {
- // 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(500).send({ 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(500).send({ 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(500).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(500).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(500).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.
- //SEQ//db.query('UPDATE users SET password=? WHERE id=?', [improvedHash, userId], function(err, result) {
- db.user.findOne({ where: { id: userId } }).then(user_db => {
- //SEQ//if (err) throw err;
- user_db.updateAttributes({
- password: improvedHash
- });
- return callback();
- });
- });
- }
- });
+function verifyHash (res, password, hash, userId, callback) {
+ // 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(500).send({ 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(500).send({ 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(500).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(500).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(500).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.
+ // SEQ//db.query('UPDATE users SET password=? WHERE id=?', [improvedHash, userId], function (err, result) {
+ db.user.findOne({ where: { id: userId } }).then(user => {
+ // SEQ//if (err) throw err;
+ user.updateAttributes({
+ password: improvedHash
+ })
+ return callback()
+ })
+ })
+ }
+ })
}
// Function for validating the e-mail.
-function validateEmail(email) {
- var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
- return re.test(String(email).toLowerCase());
+function validateEmail (email) {
+// var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
+// Removed escape before [ because eslint told me so.
+ var re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
+ return re.test(String(email).toLowerCase())
}
// Function for validating the password. Password requirements are implemented here.
-function validatePassword(password) {
- // TODO: implement pw requirements like in the frontend.
- return true;
-} \ No newline at end of file
+function validatePassword (password) {
+ // TODO: implement pw requirements like in the frontend.
+ return true
+}