Completed login token support.

This commit is contained in:
Ylian Saint-Hilaire 2021-04-16 18:55:03 -07:00
parent 6c3e010ce9
commit 8ce24152f4
6 changed files with 2396 additions and 2168 deletions

View File

@ -95,6 +95,13 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
const Wsman = require('./amt/amt-wsman.js');
const Amt = require('./amt/amt.js');
// If this session has an expire time, setup a timer now.
if ((req.session != null) && (typeof req.session.expire == 'number')) {
var delta = (req.session.expire - Date.now());
if (delta <= 0) { req.session = {}; try { ws.close(); } catch (ex) { } return; } // Session is already expired, close now.
obj.expireTimer = setTimeout(function () { for (var i in req.session) { delete req.session[i]; } obj.close(); }, delta);
}
// Send a message to the user
//obj.send = function (data) { try { if (typeof data == 'string') { ws.send(Buffer.from(data, 'binary')); } else { ws.send(data); } } catch (e) { } }
@ -118,6 +125,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
if (obj.pingtimer) { clearInterval(obj.pingtimer); delete obj.pingtimer; }
if (obj.pongtimer) { clearInterval(obj.pongtimer); delete obj.pongtimer; }
// Clear expire timeout
if (obj.expireTimer != null) { clearTimeout(obj.expireTimer); delete obj.expireTimer; }
// Perform cleanup
parent.parent.RemoveAllEventDispatch(ws);
if (obj.serverStatsTimer != null) { clearInterval(obj.serverStatsTimer); delete obj.serverStatsTimer; }
@ -340,6 +350,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
// Handle events
ws.HandleEvent = function (source, event, ids, id) {
// If this session is logged in using a loginToken and the token is removed, disconnect.
if ((req.session.loginToken != null) && (typeof event == 'object') && (event.action == 'loginTokenChanged') && (event.removed != null) && (event.removed.indexOf(req.session.loginToken) >= 0)) { delete req.session; obj.close(); return; }
// Normally, only allow this user to receive messages from it's own domain.
// If the user is a cross domain administrator, allow some select messages from different domains.
if ((event.domain == null) || (event.domain == domain.id) || ((obj.crossDomain === true) && (allowedCrossDomainMessages.indexOf(event.action) >= 0))) {
@ -874,6 +887,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
}
case 'serverconsole':
{
// Do not allow this command when logged in using a login token
if (req.session.loginToken != null) break;
// This is a server console message, only process this if full administrator
if (user.siteadmin != SITERIGHT_ADMIN) break;
@ -1573,6 +1589,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
}
case 'changelang':
{
// Do not allow this command when logged in using a login token
if (req.session.loginToken != null) break;
// If this account is settings locked, return here.
if ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 1024) != 0)) return;
@ -1599,6 +1618,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
}
case 'changeemail':
{
// Do not allow this command when logged in using a login token
if (req.session.loginToken != null) break;
// If the email is the username, this command is not allowed.
if (domain.usernameisemail) return;
@ -1650,6 +1672,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
}
case 'verifyemail':
{
// Do not allow this command when logged in using a login token
if (req.session.loginToken != null) break;
// If this account is settings locked, return here.
if ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 1024) != 0)) return;
@ -1795,6 +1820,11 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
db.Remove('ntp' + deluser._id); // Remove personal notes for this user
db.Remove('im' + deluser._id); // Remove image for this user
// Delete any login tokens
parent.parent.db.GetAllTypeNodeFiltered(['logintoken-' + deluser._id], domain.id, 'logintoken', null, function (err, docs) {
if ((err == null) && (docs != null)) { for (var i = 0; i < docs.length; i++) { parent.parent.db.Remove(docs[i]._id, function () { }); } }
});
// Delete all files on the server for this account
try {
var deluserpath = parent.getServerRootFilePath(deluser);
@ -2209,6 +2239,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
}
case 'updateUserImage':
{
if (req.session.loginToken != null) break; // Do not allow this command when logged in using a login token
var uid = user._id;
if ((typeof command.userid == 'string') && ((user.siteadmin & SITERIGHT_MANAGEUSERS) != 0)) { uid = command.userid; }
@ -2653,6 +2685,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
}
case 'changepassword':
{
// Do not allow this command when logged in using a login token
if (req.session.loginToken != null) break;
// If this account is settings locked, return here.
if ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 1024) != 0)) return;
@ -2878,6 +2913,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
}
case 'serverversion':
{
// Do not allow this command when logged in using a login token
if (req.session.loginToken != null) break;
// Check the server version
if ((user.siteadmin & 16) == 0) break;
if ((domain.myserver === false) || ((domain.myserver != null) && (domain.myserver !== true) && (domain.myserver.upgrade !== true))) break;
@ -2887,6 +2925,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
}
case 'serverupdate':
{
// Do not allow this command when logged in using a login token
if (req.session.loginToken != null) break;
// Perform server update
if ((user.siteadmin & 16) == 0) break;
if ((domain.myserver === false) || ((domain.myserver != null) && (domain.myserver !== true) && (domain.myserver.upgrade !== true))) break;
@ -4357,6 +4398,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
}
case 'otpemail':
{
// Do not allow this command when logged in using a login token
if (req.session.loginToken != null) break;
if ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 1024) != 0)) return; // If this account is settings locked, return here.
// Check input
@ -4381,6 +4425,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
}
case 'otpauth-request':
{
// Do not allow this command when logged in using a login token
if (req.session.loginToken != null) break;
if ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 1024) != 0)) return; // If this account is settings locked, return here.
// Check if 2-step login is supported
@ -4400,6 +4447,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
}
case 'otpauth-setup':
{
// Do not allow this command when logged in using a login token
if (req.session.loginToken != null) break;
if ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 1024) != 0)) return; // If this account is settings locked, return here.
// Check if 2-step login is supported
@ -4430,6 +4480,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
}
case 'otpauth-clear':
{
// Do not allow this command when logged in using a login token
if (req.session.loginToken != null) break;
if ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 1024) != 0)) return; // If this account is settings locked, return here.
// Check if 2-step login is supported
@ -4455,6 +4508,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
}
case 'otpauth-getpasswords':
{
// Do not allow this command when logged in using a login token
if (req.session.loginToken != null) break;
// Check if 2-step login is supported
const twoStepLoginSupported = ((parent.parent.config.settings.no2factorauth !== true) && (domain.auth != 'sspi') && (parent.parent.certificates.CommonName.indexOf('.') != -1) && (args.nousers !== true));
if (twoStepLoginSupported == false) break;
@ -4500,6 +4556,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
}
case 'otp-hkey-get':
{
// Do not allow this command when logged in using a login token
if (req.session.loginToken != null) break;
// Check if 2-step login is supported
const twoStepLoginSupported = ((parent.parent.config.settings.no2factorauth !== true) && (domain.auth != 'sspi') && (parent.parent.certificates.CommonName.indexOf('.') != -1) && (args.nousers !== true));
if (twoStepLoginSupported == false) break;
@ -4513,6 +4572,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
}
case 'otp-hkey-remove':
{
// Do not allow this command when logged in using a login token
if (req.session.loginToken != null) break;
if ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 1024) != 0)) return; // If this account is settings locked, return here.
// Check if 2-step login is supported
@ -4537,6 +4599,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
}
case 'otp-hkey-yubikey-add':
{
// Do not allow this command when logged in using a login token
if (req.session.loginToken != null) break;
if ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 1024) != 0)) return; // If this account is settings locked, return here.
// Yubico API id and signature key can be requested from https://upgrade.yubico.com/getapikey/
@ -4592,6 +4657,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
}
case 'otpdev-clear':
{
// Do not allow this command when logged in using a login token
if (req.session.loginToken != null) break;
// Remove the authentication push notification device
if (user.otpdev != null) {
// Change the user
@ -4609,6 +4677,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
}
case 'otpdev-set':
{
// Do not allow this command when logged in using a login token
if (req.session.loginToken != null) break;
// Attempt to add a authentication push notification device
// This will only send a push notification to the device, the device needs to confirm for the auth device to be added.
if (common.validateString(command.nodeid, 1, 1024) == false) break; // Check nodeid
@ -4635,6 +4706,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
}
case 'webauthn-startregister':
{
// Do not allow this command when logged in using a login token
if (req.session.loginToken != null) break;
if ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 1024) != 0)) return; // If this account is settings locked, return here.
// Check if 2-step login is supported
@ -4649,6 +4723,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
}
case 'webauthn-endregister':
{
// Do not allow this command when logged in using a login token
if (req.session.loginToken != null) break;
if ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 1024) != 0)) return; // If this account is settings locked, return here.
const twoStepLoginSupported = ((parent.parent.config.settings.no2factorauth !== true) && (domain.auth != 'sspi') && (parent.parent.certificates.CommonName.indexOf('.') != -1) && (args.nousers !== true));
if ((twoStepLoginSupported == false) || (obj.webAuthnReqistrationRequest == null)) return;
@ -4689,6 +4766,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
break;
}
case 'verifyPhone': {
// Do not allow this command when logged in using a login token
if (req.session.loginToken != null) break;
if ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 1024) != 0)) return; // If this account is settings locked, return here.
if (parent.parent.smsserver == null) return;
if (common.validateString(command.phone, 1, 18) == false) break; // Check phone length
@ -4702,6 +4782,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
break;
}
case 'confirmPhone': {
// Do not allow this command when logged in using a login token
if (req.session.loginToken != null) break;
if ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 1024) != 0)) return; // If this account is settings locked, return here.
if ((parent.parent.smsserver == null) || (typeof command.cookie != 'string') || (typeof command.code != 'string') || (obj.failedSmsCookieCheck == 1)) break; // Input checks
var cookie = parent.parent.decodeCookie(command.cookie);
@ -4729,6 +4812,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
break;
}
case 'removePhone': {
// Do not allow this command when logged in using a login token
if (req.session.loginToken != null) break;
if ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 1024) != 0)) return; // If this account is settings locked, return here.
if (user.phone == null) break;
@ -5381,6 +5467,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
break;
}
case 'serverBackup': {
// Do not allow this command when logged in using a login token
if (req.session.loginToken != null) break;
if ((user.siteadmin != SITERIGHT_ADMIN) || (typeof parent.parent.config.settings.autobackup.googledrive != 'object')) return;
if (command.service == 'googleDrive') {
if (command.state == 0) {
@ -5403,6 +5492,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
break;
}
case 'twoFactorCookie': {
// Do not allow this command when logged in using a login token
if (req.session.loginToken != null) break;
// Generate a two-factor cookie
if (((domain.twofactorcookiedurationdays == null) || (domain.twofactorcookiedurationdays > 0))) {
var maxCookieAge = domain.twofactorcookiedurationdays;
@ -5611,6 +5703,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
break;
}
case 'loginTokens': { // Respond with the list of currently valid login tokens
if (req.session.loginToken != null) break; // Do not allow this command when logged in using a login token
if ((typeof domain.passwordrequirements != 'object') && (domain.passwordrequirements.logintokens == false)) break; // Login tokens are not supported on this server
// If remove is an array or strings, we are going to be removing these and returning the results.
@ -5618,12 +5711,12 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
parent.db.GetAllTypeNodeFiltered(['logintoken-' + user._id], domain.id, 'logintoken', null, function (err, docs) {
if (err != null) return;
var now = Date.now(), removed = 0, okDocs = [];
var now = Date.now(), removed = [], okDocs = [];
for (var i = 0; i < docs.length; i++) {
const doc = docs[i];
if (((doc.expire != 0) && (doc.expire < now)) || (doc.tokenUser == null) || ((command.remove != null) && (command.remove.indexOf(doc.tokenUser) >= 0))) {
// This share is expired.
parent.db.Remove(doc._id, function () { }); removed++;
parent.db.Remove(doc._id, function () { }); removed.push(doc.tokenUser);
} else {
// This share is ok, remove extra data we don't need to send.
delete doc._id; delete doc.domain; delete doc.nodeid; delete doc.type; delete doc.userid; delete doc.salt; delete doc.hash;
@ -5633,17 +5726,18 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
try { ws.send(JSON.stringify({ action: 'loginTokens', loginTokens: okDocs })); } catch (ex) { }
// If any login tokens where removed, event the change.
if (removed > 0) {
if (removed.length > 0) {
// Dispatch the new event
var targets = ['*', 'server-users', user._id];
if (user.groups) { for (var i in user.groups) { targets.push('server-users:' + i); } }
var event = { etype: 'user', userid: user._id, username: user.name, action: 'loginTokenChanged', domain: domain.id, loginTokens: okDocs, nolog: 1 };
var event = { etype: 'user', userid: user._id, username: user.name, action: 'loginTokenChanged', domain: domain.id, loginTokens: okDocs, removed: removed, nolog: 1 };
parent.parent.DispatchEvent(targets, obj, event);
}
});
break;
}
case 'createLoginToken': { // Create a new login token
if (req.session.loginToken != null) break; // Do not allow this command when logged in using a login token
if ((typeof domain.passwordrequirements != 'object') && (domain.passwordrequirements.logintokens == false)) break; // Login tokens are not supported on this server
if (common.validateString(command.name, 1, 100) == false) break; // Check name
if ((typeof command.expire != 'number') || (command.expire < 0)) break; // Check expire

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -1349,12 +1349,12 @@
}
function updateSelf() {
var accountSettingsLocked = false;
if (userinfo) { accountSettingsLocked = ((userinfo.siteadmin != 0xFFFFFFFF) && ((userinfo.siteadmin & 1024) != 0)); }
var accountSettingsLocked = ((features2 & 0x100) != 0);
if (userinfo) { accountSettingsLocked = ((userinfo.siteadmin != 0xFFFFFFFF) && ((userinfo.siteadmin & 1024) != 0)) || ((features2 & 0x100) != 0); } // Not admin and have account features locked, or using a loginToken
QV('p3AccountActions', ((features & 4) == 0) && (serverinfo.domainauth == false) && (accountSettingsLocked == false)); // Hide Account Actions if in single user mode or domain authentication
QV('logoutMenuOption', ((features & 4) == 0) && (serverinfo.domainauth == false)); // Hide logout if in single user mode or domain authentication
QV('p2AccountSecurity', ((features & 4) == 0) && (serverinfo.domainauth == false) && ((features & 4096) != 0) && (accountSettingsLocked == false)); // Hide Account Security if in single user mode or domain authentication, 2 factor auth not supported.
QV('p2AccountImage', !accountSettingsLocked);
QV('verifyEmailId', (userinfo.emailVerified !== true) && (userinfo.email != null) && (serverinfo.emailcheck == true));
QV('manageAuthApp', features & 4096);
QV('manageOtp', ((features & 4096) != 0) && ((userinfo.otpsecret == 1) || (userinfo.otphkeys > 0)));

View File

@ -1928,7 +1928,7 @@
function updateSiteAdmin() {
var serverFeatures = parseInt('{{{serverfeatures}}}');
var siteRights = userinfo.siteadmin;
var accountSettingsLocked = ((siteRights != 0xFFFFFFFF) && ((siteRights & 1024) != 0));
var accountSettingsLocked = ((siteRights != 0xFFFFFFFF) && ((siteRights & 1024) != 0)) || ((features2 & 0x100) != 0); // Not admin and have account features locked, or using a loginToken
// Update account actions
QV('p2AccountSecurity', ((features & 4) == 0) && (serverinfo.domainauth == false) && ((features & 4096) != 0) && (accountSettingsLocked == false)); // Hide Account Security if in single user mode or domain authentication, 2 factor auth not supported.
@ -1939,7 +1939,7 @@
QV('p2AccountPassActions', ((features & 4) == 0) && (serverinfo.domainauth == false) && (userinfo != null) && (userinfo._id.split('/')[2].startsWith('~') == false)); // Hide Account Actions if in single user mode or domain authentication
//QV('p2AccountImage', ((features & 4) == 0) && (serverinfo.domainauth == false)); // If account actions are not visible, also remove the image on that panel
QV('accountCreateLoginTokenSpan', features2 & 0x00000080);
QV('p2AccountImage', !accountSettingsLocked)
QV('p2AccountImageFrame', !accountSettingsLocked)
QV('p2ServerActions', (siteRights & 21) && ((serverFeatures & 15) != 0));
QV('LeftMenuMyServer', (siteRights & 21) && ((serverFeatures & 64) != 0)); // 16 + 4 + 1
QV('MainMenuMyServer', siteRights & 21);
@ -10211,6 +10211,7 @@
x += addHtmlValue("Expire Time", '<select id=d2tokenExpire style=width:250px>' + y + '</select>');
setDialogMode(2, "Create Login Token", 3, account_createLoginTokenEx, x);
QE('idx_dlgOkButton', false);
Q('d2tokenName').focus();
}
function account_createLoginTokenValidate() {

View File

@ -1164,6 +1164,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
delete req.session.messageid;
delete req.session.passhint;
delete req.session.cuserid;
delete req.session.expire;
req.session.userid = userid;
req.session.domainid = domain.id;
req.session.currentNode = '';
@ -1205,6 +1206,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
if (domain == null) { return; }
if ((domain.auth == 'sspi') || (domain.auth == 'ldap')) { parent.debug('web', 'handleCreateAccountRequest: failed checks.'); res.sendStatus(404); return; }
if ((domain.loginkey != null) && (domain.loginkey.indexOf(req.query.key) == -1)) { res.sendStatus(404); return; } // Check 3FA URL key
if (req.session.loginToken != null) { res.sendStatus(404); return; } // Do not allow this command when logged in using a login token
// Check if we are in maintenance mode
if (parent.config.settings.maintenancemode != null) {
@ -1359,6 +1361,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
const domain = checkUserIpAddress(req, res);
if (domain == null) { return; }
if ((domain.loginkey != null) && (domain.loginkey.indexOf(req.query.key) == -1)) { res.sendStatus(404); return; } // Check 3FA URL key
if (req.session.loginToken != null) { res.sendStatus(404); return; } // Do not allow this command when logged in using a login token
// Check everything is ok
if ((domain == null) || (domain.auth == 'sspi') || (domain.auth == 'ldap') || (typeof req.body.rpassword1 != 'string') || (typeof req.body.rpassword2 != 'string') || (req.body.rpassword1 != req.body.rpassword2) || (typeof req.body.rpasswordhint != 'string') || (req.session == null) || (typeof req.session.resettokenusername != 'string') || (typeof req.session.resettokenpassword != 'string')) {
@ -1472,6 +1475,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
if (domain == null) { return; }
if ((domain.auth == 'sspi') || (domain.auth == 'ldap') || (obj.args.lanonly == true) || (obj.parent.certificates.CommonName == null) || (obj.parent.certificates.CommonName.indexOf('.') == -1)) { parent.debug('web', 'handleResetAccountRequest: check failed'); res.sendStatus(404); return; }
if ((domain.loginkey != null) && (domain.loginkey.indexOf(req.query.key) == -1)) { res.sendStatus(404); return; } // Check 3FA URL key
if (req.session.loginToken != null) { res.sendStatus(404); return; } // Do not allow this command when logged in using a login token
// Always lowercase the email address
if (req.body.email) { req.body.email = req.body.email.toLowerCase(); }
@ -1591,6 +1595,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
if (domain == null) { return; }
if ((domain.mailserver == null) || (domain.auth == 'sspi') || (domain.auth == 'ldap') || (typeof req.session.cuserid != 'string') || (obj.users[req.session.cuserid] == null) || (!obj.common.validateEmail(req.body.email, 1, 256))) { parent.debug('web', 'handleCheckAccountEmailRequest: failed checks.'); res.sendStatus(404); return; }
if ((domain.loginkey != null) && (domain.loginkey.indexOf(req.query.key) == -1)) { res.sendStatus(404); return; } // Check 3FA URL key
if (req.session.loginToken != null) { res.sendStatus(404); return; } // Do not allow this command when logged in using a login token
// Always lowercase the email address
if (req.body.email) { req.body.email = req.body.email.toLowerCase(); }
@ -1980,6 +1985,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
if (domain == null) { return; }
if ((domain.auth == 'sspi') || (domain.auth == 'ldap')) { parent.debug('web', 'handleDeleteAccountRequest: failed checks.'); res.sendStatus(404); return; }
if ((domain.loginkey != null) && (domain.loginkey.indexOf(req.query.key) == -1)) { res.sendStatus(404); return; } // Check 3FA URL key
if (req.session.loginToken != null) { res.sendStatus(404); return; } // Do not allow this command when logged in using a login token
var user = null;
if (req.body.authcookie) {
@ -2056,6 +2062,17 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
obj.db.Remove('ntp' + deluser._id); // Remove personal notes for this user
obj.db.Remove('im' + deluser._id); // Remove image for this user
// Delete any login tokens
parent.db.GetAllTypeNodeFiltered(['logintoken-' + deluser._id], domain.id, 'logintoken', null, function (err, docs) {
if ((err == null) && (docs != null)) { for (var i = 0; i < docs.length; i++) { parent.db.Remove(docs[i]._id, function () { }); } }
});
// Delete all files on the server for this account
try {
var deluserpath = obj.getServerRootFilePath(deluser);
if (deluserpath != null) { obj.deleteFolderRec(deluserpath); }
} catch (e) { }
// Remove the user
obj.db.Remove(deluser._id);
delete obj.users[deluser._id];
@ -2151,6 +2168,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
if (domain == null) { return; }
if ((domain.auth == 'sspi') || (domain.auth == 'ldap')) { parent.debug('web', 'handlePasswordChangeRequest: failed checks (1).'); res.sendStatus(404); return; }
if ((domain.loginkey != null) && (domain.loginkey.indexOf(req.query.key) == -1)) { res.sendStatus(404); return; } // Check 3FA URL key
if (req.session.loginToken != null) { res.sendStatus(404); return; } // Do not allow this command when logged in using a login token
// Check if the user is logged and we have all required parameters
if (!req.session || !req.session.userid || !req.body.apassword0 || !req.body.apassword1 || (req.body.apassword1 != req.body.apassword2) || (req.session.domainid != domain.id)) {
@ -2325,6 +2343,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
if ((domain.loginkey != null) && (domain.loginkey.indexOf(req.query.key) == -1)) { res.sendStatus(404); return; } // Check 3FA URL key
if (!obj.args) { parent.debug('web', 'handleRootRequest: no obj.args.'); res.sendStatus(500); return; }
// If the session is expired, clear it.
if ((req.session != null) && (typeof req.session.expire == 'number') && ((req.session.expire - Date.now()) <= 0)) { for (var i in req.session) { delete req.session[i]; } }
// Check if we are in maintenance mode
if ((parent.config.settings.maintenancemode != null) && (req.query.admin !== '1')) {
parent.debug('web', 'handleLoginRequest: Server under maintenance.');
@ -2584,6 +2605,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
if (parent.amtProvisioningServer != null) { features2 += 0x00000020; } // Intel AMT LAN provisioning server
if (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.push2factor != false)) && (obj.parent.firebase != null)) { features2 += 0x00000040; } // Indicates device push notification 2FA is enabled
if ((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.logintokens != false)) { features2 += 0x00000080; } // Indicates login tokens are allowed
if (req.session.loginToken != null) { features2 += 0x00000100; } // LoginToken mode, no account changes.
// Create a authentication cookie
const authCookie = obj.parent.encodeCookie({ userid: dbGetFunc.user._id, domainid: domain.id, ip: req.clientIp }, obj.parent.loginCookieEncryptionKey);
@ -6095,6 +6117,11 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
// Authenticates a session and forwards
function PerformWSSessionAuth(ws, req, noAuthOk, func) {
// Check if the session expired
if ((req.session != null) && (typeof req.session.expire == 'number') && (req.session.expire <= Date.now())) {
parent.debug('web', 'WSERROR: Session expired.'); try { ws.send(JSON.stringify({ action: 'close', cause: 'expired', msg: 'expired-1' })); ws.close(); } catch (e) { } return;
}
// Check if this is a banned ip address
if (obj.checkAllowLogin(req) == false) { parent.debug('web', 'WSERROR: Banned connection.'); try { ws.send(JSON.stringify({ action: 'close', cause: 'banned', msg: 'banned-1' })); ws.close(); } catch (e) { } return; }
try {