1
0
Fork 0
auth.rxbn.de/bin/web/routes/api/login.js

216 lines
6.1 KiB
JavaScript

var sanitize = require('mongo-sanitize');
var speakeasy = require('speakeasy');
var cfg = require(global['__dirname']+'/bin/config');
let db = global['requireModule']('database');
module.exports = {
path: "/login",
/**
* login a user
* @url /api/login
* @method POST
* @POST ['email', 'password']
*/
post: async (req, res) => {
// if user is logged in (existing session); check MFA
if(req.session.user) {
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'
]
}));
}
if(Date.now() > req.session.user.loginTimeout + cfg.web.loginTimeout) {
res.clearCookie('RememberMe');
req.session.destroy();
return res.type('json').status(401).end(JSON.stringify({
status: 401,
message: '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;
delete req.session.user.loginTimeout;
return res.type('json').end(JSON.stringify({
status: 200,
message: 'msg.auth.login.successful',
type: 'form' // TODO: types - { form, access_app}
}));
} 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
if(!req.body.email || !req.body.password) {
return res.type('json').status(401).end(JSON.stringify({
status: 401,
message: [
'msg.request.data.missing',
'msg.auth.login.failed'
]
}));
}
let email = sanitize(req.body.email);
let pass = sanitize(req.body.password);
// database query: get user by email
user = await db.getUser(email);
// 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 || !global['requireModule']('auth').validateHash(user.reply.passhash, pass)) {
return res.type('json').status(401).end(JSON.stringify({
status: 401,
message: 'msg.auth.login.failed'
}));
// do login
} else {
// add cookies; login
// new activity 'action.user.login'
// add session data
req.session.user = {
'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;
req.session.user.login_timeout = Date.now();
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}
}));
}
}
}
};