|
|
|
@ -1,4 +1,5 @@
|
|
|
|
|
var sanitize = require('mongo-sanitize');
|
|
|
|
|
var speakeasy = require('speakeasy');
|
|
|
|
|
let db = global['requireModule']('database');
|
|
|
|
|
|
|
|
|
|
module.exports = {
|
|
|
|
@ -10,12 +11,117 @@ module.exports = {
|
|
|
|
|
* @POST ['email', 'password']
|
|
|
|
|
*/
|
|
|
|
|
post: async (req, res) => {
|
|
|
|
|
// if user is logged in (existing session); FAIL
|
|
|
|
|
// if user is logged in (existing session); check MFA
|
|
|
|
|
if(req.session.user) {
|
|
|
|
|
return res.type('json').end(JSON.stringify({
|
|
|
|
|
status: 401,
|
|
|
|
|
message: 'msg.auth.logout.required'
|
|
|
|
|
}));
|
|
|
|
|
if(!req.session.user.loggedInFull) {
|
|
|
|
|
if(!req.body.mfa) {
|
|
|
|
|
return res.type('json').status(401).end(JSON.stringify({
|
|
|
|
|
status: 401,
|
|
|
|
|
message: [
|
|
|
|
|
'msg.request.data.missing',
|
|
|
|
|
'msg.auth.login.failed'
|
|
|
|
|
]
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
let mfa = sanitize(req.body.mfa);
|
|
|
|
|
user = await db.getUser(req.session.user.id);
|
|
|
|
|
|
|
|
|
|
// if database error
|
|
|
|
|
if(user.err) {
|
|
|
|
|
// log error while debugging
|
|
|
|
|
global['logs'].debug(user.err);
|
|
|
|
|
|
|
|
|
|
// login failed because of database error
|
|
|
|
|
return res.type('json').status(500).end(JSON.stringify({
|
|
|
|
|
status: 500,
|
|
|
|
|
message: [
|
|
|
|
|
'msg.database.error',
|
|
|
|
|
'msg.auth.login.failed'
|
|
|
|
|
]
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// no reply (user does not exist) or password is wrong
|
|
|
|
|
if(!user.reply || user.reply === null || user.reply.length == 0 || user.reply.length > 1) {
|
|
|
|
|
return res.type('json').status(401).end(JSON.stringify({
|
|
|
|
|
status: 401,
|
|
|
|
|
message: 'msg.auth.login.failed'
|
|
|
|
|
}));
|
|
|
|
|
// do login
|
|
|
|
|
} else {
|
|
|
|
|
if(req.session.user.login_step+1 <= user.reply.mfa.data.length) {
|
|
|
|
|
let test = false;
|
|
|
|
|
switch (req.session.user.login_step_type) {
|
|
|
|
|
case "TOTP":
|
|
|
|
|
test = speakeasy.totp.verify({
|
|
|
|
|
secret: user.reply.mfa.data[req.session.user.login_step].data,
|
|
|
|
|
encoding: 'base32',
|
|
|
|
|
token: mfa
|
|
|
|
|
});
|
|
|
|
|
break;
|
|
|
|
|
case "HOTP":
|
|
|
|
|
test = speakeasy.hotp.verify({
|
|
|
|
|
secret: user.reply.mfa.data[req.session.user.login_step].data.split("|")[0],
|
|
|
|
|
counter: user.reply.mfa.data[req.session.user.login_step].data.split("|")[1],
|
|
|
|
|
encoding: 'base32',
|
|
|
|
|
token: mfa
|
|
|
|
|
});
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(test) {
|
|
|
|
|
if(req.session.user.login_step+1 >= user.reply.mfa.data.length) {
|
|
|
|
|
req.session.user.loggedInFull = true;
|
|
|
|
|
delete req.session.user.login_step;
|
|
|
|
|
delete req.session.user.login_step_type;
|
|
|
|
|
} else {
|
|
|
|
|
req.session.user.login_step++;
|
|
|
|
|
req.session.user.login_step_type = user.reply.mfa.data[req.session.user.login_step].type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res.type('json').end(JSON.stringify({
|
|
|
|
|
status: 200,
|
|
|
|
|
message: 'msg.auth.login.mfa',
|
|
|
|
|
type: 'form' // TODO: types - { form, access_app}
|
|
|
|
|
}));
|
|
|
|
|
} else {
|
|
|
|
|
if(req.session.user.login_step_type == 'HOTP') {
|
|
|
|
|
let mfaobj = user.reply.mfa;
|
|
|
|
|
mfaobj[req.session.user.login_step].data = user.reply.mfa[req.session.user.login_step].data.split("|")[0] + (user.reply.mfa[req.session.user.login_step].data.split("|")[1]++);
|
|
|
|
|
|
|
|
|
|
await db.updateUser(user.id, {
|
|
|
|
|
mfa: mfaobj
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
return res.type('json').status(401).end(JSON.stringify({
|
|
|
|
|
status: 401,
|
|
|
|
|
message: [
|
|
|
|
|
'msg.auth.login.failed',
|
|
|
|
|
'msg.auth.login.mfa'
|
|
|
|
|
]
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res.type('json').end(JSON.stringify({
|
|
|
|
|
status: 200,
|
|
|
|
|
message: 'msg.auth.login.mfa',
|
|
|
|
|
type: 'form' // TODO: types - { form, access_app}
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
return res.type('json').status(401).end(JSON.stringify({
|
|
|
|
|
status: 401,
|
|
|
|
|
message: [
|
|
|
|
|
'msg.request.data.missing',
|
|
|
|
|
'msg.auth.login.failed'
|
|
|
|
|
]
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
return res.type('json').end(JSON.stringify({
|
|
|
|
|
status: 401,
|
|
|
|
|
message: 'msg.auth.logout.required'
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// check body variables
|
|
|
|
@ -65,12 +171,23 @@ module.exports = {
|
|
|
|
|
'id': user.reply._id,
|
|
|
|
|
'group': user.reply.group
|
|
|
|
|
};
|
|
|
|
|
req.session.user.loggedInFull = user.reply.mfa.active == false; // mfa active?
|
|
|
|
|
if(!req.session.user.loggedInFull) { // mfa is active
|
|
|
|
|
req.session.user.login_step_type = user.reply.mfa.data[0].type;
|
|
|
|
|
req.session.user.login_step = 0;
|
|
|
|
|
|
|
|
|
|
return res.type('json').end(JSON.stringify({
|
|
|
|
|
status: 200,
|
|
|
|
|
message: 'msg.auth.login.successful',
|
|
|
|
|
type: 'form' // TODO: types - { form, access_app}
|
|
|
|
|
}));
|
|
|
|
|
return res.type('json').end(JSON.stringify({
|
|
|
|
|
status: 200,
|
|
|
|
|
message: 'msg.auth.login.mfa',
|
|
|
|
|
type: 'form' // TODO: types - { form, access_app}
|
|
|
|
|
}));
|
|
|
|
|
} else {
|
|
|
|
|
return res.type('json').end(JSON.stringify({
|
|
|
|
|
status: 200,
|
|
|
|
|
message: 'msg.auth.login.successful',
|
|
|
|
|
type: 'form' // TODO: types - { form, access_app}
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|