HTTP cookie session size reduction.

Ylian Saint-Hilaire committed May 12, 2021 at 10:34 UTC e012e1427ec0d60db094435deca9bd54fabf33b5
1 file changed +113 -111
webserver.js
+113 -111
@@ -855,7 +855,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
855 if (httpport != 443) { origin += ':' + httpport; }
856
857 var assertionExpectations = {
858 - challenge: req.session.u2fchallenge,
858 + challenge: req.session.u2f,
859 origin: origin,
860 factor: 'either',
861 fmt: 'fido-u2f',
@@ -934,7 +934,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
934
935 // Return a U2F hardware key challenge
936 function getHardwareKeyChallenge(req, domain, user, func) {
937 - if (req.session.u2fchallenge) { delete req.session.u2fchallenge; };
937 + delete req.session.u2f;
938 if (user.otphkeys && (user.otphkeys.length > 0)) {
939 // Get all WebAuthn keys
940 var webAuthnKeys = [];
@@ -943,7 +943,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
943 // Generate a Webauthn challenge, this is really easy, no need to call any modules to do this.
944 var authnOptions = { type: 'webAuthn', keyIds: [], timeout: 60000, challenge: obj.crypto.randomBytes(64).toString('base64') };
945 for (var i = 0; i < webAuthnKeys.length; i++) { authnOptions.keyIds.push(webAuthnKeys[i].keyId); }
946 - req.session.u2fchallenge = authnOptions.challenge;
946 + req.session.u2f = authnOptions.challenge;
947 parent.debug('web', 'getHardwareKeyChallenge: success');
948 func(JSON.stringify(authnOptions));
949 return;
@@ -977,7 +977,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
977
978 // Normally, use the body username/password. If this is a token, use the username/password in the session.
979 var xusername = req.body.username, xpassword = req.body.password;
980 - if ((xusername == null) && (xpassword == null) && (req.body.token != null)) { xusername = req.session.tokenusername; xpassword = req.session.tokenpassword; }
980 + if ((xusername == null) && (xpassword == null) && (req.body.token != null)) { xusername = req.session.tuser; xpassword = req.session.tpass; }
981
982 // Authenticate the user
983 obj.authenticate(xusername, xpassword, domain, function (err, userid, passhint, loginOptions) {
@@ -987,7 +987,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
987 // Check if we are in maintenance mode
988 if ((parent.config.settings.maintenancemode != null) && (user.siteadmin != 4294967295)) {
989 req.session.messageid = 115; // Server under maintenance
990 - req.session.loginmode = '1';
990 + req.session.loginmode = 1;
991 if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); }
992 return;
993 }
@@ -997,14 +997,14 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
997 var push2fa = ((parent.firebase != null) && (user.otpdev != null));
998
999 // Check if this user has 2-step login active
1000 - if ((req.session.loginmode != '6') && checkUserOneTimePasswordRequired(domain, user, req, loginOptions)) {
1000 + if ((req.session.loginmode != 6) && checkUserOneTimePasswordRequired(domain, user, req, loginOptions)) {
1001 if ((req.body.hwtoken == '**email**') && email2fa) {
1002 user.otpekey = { k: obj.common.zeroPad(getRandomEightDigitInteger(), 8), d: Date.now() };
1003 obj.db.SetUser(user);
1004 parent.debug('web', 'Sending 2FA email to: ' + user.email);
1005 domain.mailserver.sendAccountLoginMail(domain, user.email, user.otpekey.k, obj.getLanguageCodes(req), req.query.key);
1006 req.session.messageid = 2; // "Email sent" message
1007 - req.session.loginmode = '4';
1007 + req.session.loginmode = 4;
1008 if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); }
1009 return;
1010 }
@@ -1017,7 +1017,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1017 parent.smsserver.sendToken(domain, user.phone, user.otpsms.k, obj.getLanguageCodes(req));
1018 // Ask for a login token & confirm sms was sent
1019 req.session.messageid = 4; // "SMS sent" message
1020 - req.session.loginmode = '4';
1020 + req.session.loginmode = 4;
1021 if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); }
1022 return;
1023 }
@@ -1048,7 +1048,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1048 // Request that the login page wait for device auth
1049 req.session.messageid = 5; // "Sending notification..." message
1050 req.session.passhint = url;
1051 - req.session.loginmode = '8';
1051 + req.session.loginmode = 8;
1052 if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); }
1053 return;
1054 }
@@ -1072,13 +1072,13 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1072
1073 // Wait and redirect the user
1074 setTimeout(function () {
1075 - req.session.loginmode = '4';
1076 - req.session.tokenemail = ((user.email != null) && (user.emailVerified == true) && (domain.mailserver != null) && (user.otpekey != null));
1077 - req.session.tokensms = ((user.phone != null) && (parent.smsserver != null));
1078 - req.session.tokenpush = ((user.otpdev != null) && (parent.firebase != null));
1079 - req.session.tokenuserid = userid;
1080 - req.session.tokenusername = xusername;
1081 - req.session.tokenpassword = xpassword;
1075 + req.session.loginmode = 4;
1076 + if ((user.email != null) && (user.emailVerified == true) && (domain.mailserver != null) && (user.otpekey != null)) { req.session.temail = 1; }
1077 + if ((user.phone != null) && (parent.smsserver != null)) { req.session.tsms = 1; }
1078 + if ((user.otpdev != null) && (parent.firebase != null)) { req.session.tpush = 1; }
1079 + req.session.tuserid = userid;
1080 + req.session.tuser = xusername;
1081 + req.session.tpass = xpassword;
1082 if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); }
1083 }, randomWaitTime);
1084 } else {
@@ -1095,7 +1095,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1095 if (emailcheck && (user.emailVerified !== true)) {
1096 parent.debug('web', 'Redirecting using ' + user.name + ' to email check login page');
1097 req.session.messageid = 3; // "Email verification required" message
1098 - req.session.loginmode = '7';
1098 + req.session.loginmode = 7;
1099 req.session.passhint = user.email;
1100 req.session.cuserid = userid;
1101 if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); }
@@ -1116,7 +1116,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1116 if (emailcheck && (user.emailVerified !== true)) {
1117 parent.debug('web', 'Redirecting using ' + user.name + ' to email check login page');
1118 req.session.messageid = 3; // "Email verification required" message
1119 - req.session.loginmode = '7';
1119 + req.session.loginmode = 7;
1120 req.session.passhint = user.email;
1121 req.session.cuserid = userid;
1122 if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); }
@@ -1170,7 +1170,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1170 if ((typeof user.passchange == 'number') && ((user.passchange == -1) || ((typeof domain.passwordrequirements == 'object') && (typeof domain.passwordrequirements.reset == 'number') && (user.passchange + (domain.passwordrequirements.reset * 86400) < Math.floor(Date.now() / 1000))))) {
1171 // Request a password change
1172 parent.debug('web', 'handleLoginRequest: login ok, password change requested');
1173 - req.session.loginmode = '6';
1173 + req.session.loginmode = 6;
1174 req.session.messageid = 113; // Password change requested.
1175 req.session.resettokenuserid = userid;
1176 req.session.resettokenusername = xusername;
@@ -1195,21 +1195,20 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1195 // Regenerate session when signing in to prevent fixation
1196 //req.session.regenerate(function () {
1197 // Store the user's primary key in the session store to be retrieved, or in this case the entire user object
1198 - delete req.session.u2fchallenge;
1198 + delete req.session.u2f;
1199 delete req.session.loginmode;
1200 - delete req.session.tokenuserid;
1201 - delete req.session.tokenusername;
1202 - delete req.session.tokenpassword;
1203 - delete req.session.tokenemail;
1204 - delete req.session.tokensms;
1205 - delete req.session.tokenpush;
1200 + delete req.session.tuserid;
1201 + delete req.session.tuser;
1202 + delete req.session.tpass;
1203 + delete req.session.temail;
1204 + delete req.session.tsms;
1205 + delete req.session.tpush;
1206 delete req.session.messageid;
1207 delete req.session.passhint;
1208 delete req.session.cuserid;
1209 delete req.session.expire;
1210 + delete req.session.currentNode;
1211 req.session.userid = userid;
1211 - req.session.domainid = domain.id;
1212 - req.session.currentNode = '';
1212 req.session.ip = req.clientIp;
1213
1214 // If a login token was used, add this information and expire time to the session.
@@ -1253,7 +1252,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1252 // Check if we are in maintenance mode
1253 if (parent.config.settings.maintenancemode != null) {
1254 req.session.messageid = 115; // Server under maintenance
1256 - req.session.loginmode = '1';
1255 + req.session.loginmode = 1;
1256 if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); }
1257 return;
1258 }
@@ -1267,7 +1266,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1266 // Accounts that start with ~ are not allowed
1267 if ((typeof req.body.username != 'string') || (req.body.username.length < 1) || (req.body.username[0] == '~')) {
1268 parent.debug('web', 'handleCreateAccountRequest: unable to create account (0)');
1270 - req.session.loginmode = '2';
1269 + req.session.loginmode = 2;
1270 req.session.messageid = 100; // Unable to create account.
1271 if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); }
1272 return;
@@ -1290,7 +1289,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1289 if (typeof req.body.email == 'string') { i = req.body.email.indexOf('@'); }
1290 if (i == -1) {
1291 parent.debug('web', 'handleCreateAccountRequest: unable to create account (1)');
1293 - req.session.loginmode = '2';
1292 + req.session.loginmode = 2;
1293 req.session.messageid = 100; // Unable to create account.
1294 if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); }
1295 return;
@@ -1299,7 +1298,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1298 for (var i in domain.newaccountemaildomains) { if (emaildomain == domain.newaccountemaildomains[i].toLowerCase()) { emailok = true; } }
1299 if (emailok == false) {
1300 parent.debug('web', 'handleCreateAccountRequest: unable to create account (2)');
1302 - req.session.loginmode = '2';
1301 + req.session.loginmode = 2;
1302 req.session.messageid = 100; // Unable to create account.
1303 if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); }
1304 return;
@@ -1310,13 +1309,13 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1309 obj.db.isMaxType(domain.limits.maxuseraccounts, 'user', domain.id, function (maxExceed) {
1310 if (maxExceed) {
1311 parent.debug('web', 'handleCreateAccountRequest: account limit reached');
1313 - req.session.loginmode = '2';
1312 + req.session.loginmode = 2;
1313 req.session.messageid = 101; // Account limit reached.
1314 if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); }
1315 } else {
1316 if (!obj.common.validateUsername(req.body.username, 1, 64) || !obj.common.validateEmail(req.body.email, 1, 256) || !obj.common.validateString(req.body.password1, 1, 256) || !obj.common.validateString(req.body.password2, 1, 256) || (req.body.password1 != req.body.password2) || req.body.username == '~' || !obj.common.checkPasswordRequirements(req.body.password1, domain.passwordrequirements)) {
1317 parent.debug('web', 'handleCreateAccountRequest: unable to create account (3)');
1319 - req.session.loginmode = '2';
1318 + req.session.loginmode = 2;
1319 req.session.messageid = 100; // Unable to create account.
1320 if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); }
1321 } else {
@@ -1324,14 +1323,14 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1323 obj.db.GetUserWithVerifiedEmail(domain.id, req.body.email, function (err, docs) {
1324 if ((docs != null) && (docs.length > 0)) {
1325 parent.debug('web', 'handleCreateAccountRequest: Existing account with this email address');
1327 - req.session.loginmode = '2';
1326 + req.session.loginmode = 2;
1327 req.session.messageid = 102; // Existing account with this email address.
1328 if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); }
1329 } else {
1330 // Check if there is domain.newAccountToken, check if supplied token is valid
1331 if ((domain.newaccountspass != null) && (domain.newaccountspass != '') && (req.body.anewaccountpass != domain.newaccountspass)) {
1332 parent.debug('web', 'handleCreateAccountRequest: Invalid account creation token');
1334 - req.session.loginmode = '2';
1333 + req.session.loginmode = 2;
1334 req.session.messageid = 103; // Invalid account creation token.
1335 if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); }
1336 return;
@@ -1339,7 +1338,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1338 // Check if user exists
1339 if (obj.users['user/' + domain.id + '/' + req.body.username.toLowerCase()]) {
1340 parent.debug('web', 'handleCreateAccountRequest: Username already exists');
1342 - req.session.loginmode = '2';
1341 + req.session.loginmode = 2;
1342 req.session.messageid = 104; // Username already exists.
1343 } else {
1344 var user = { type: 'user', _id: 'user/' + domain.id + '/' + req.body.username.toLowerCase(), name: req.body.username, email: req.body.email, creation: Math.floor(Date.now() / 1000), login: Math.floor(Date.now() / 1000), domain: domain.id };
@@ -1373,7 +1372,6 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1372
1373 obj.users[user._id] = user;
1374 req.session.userid = user._id;
1376 - req.session.domainid = domain.id;
1375 req.session.ip = req.clientIp; // Bind this session to the IP address of the request
1376 // Create a user, generate a salt and hash the password
1377 require('./pass').hash(req.body.password1, function (err, salt, hash, tag) {
@@ -1408,17 +1406,17 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1406 // Check everything is ok
1407 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')) {
1408 parent.debug('web', 'handleResetPasswordRequest: checks failed');
1411 - delete req.session.u2fchallenge;
1409 + delete req.session.u2f;
1410 delete req.session.loginmode;
1413 - delete req.session.tokenuserid;
1414 - delete req.session.tokenusername;
1415 - delete req.session.tokenpassword;
1411 + delete req.session.tuserid;
1412 + delete req.session.tuser;
1413 + delete req.session.tpass;
1414 delete req.session.resettokenuserid;
1415 delete req.session.resettokenusername;
1416 delete req.session.resettokenpassword;
1419 - delete req.session.tokenemail;
1420 - delete req.session.tokensms;
1421 - delete req.session.tokenpush;
1417 + delete req.session.temail;
1418 + delete req.session.tsms;
1419 + delete req.session.tpush;
1420 delete req.session.messageid;
1421 delete req.session.passhint;
1422 delete req.session.cuserid;
@@ -1435,7 +1433,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1433 // If we have password requirements, check this here.
1434 if (!obj.common.checkPasswordRequirements(req.body.rpassword1, domain.passwordrequirements)) {
1435 parent.debug('web', 'handleResetPasswordRequest: password rejected, use a different one (1)');
1438 - req.session.loginmode = '6';
1436 + req.session.loginmode = 6;
1437 req.session.messageid = 105; // Password rejected, use a different one.
1438 if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); }
1439 return;
@@ -1446,7 +1444,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1444 if (result != 0) {
1445 // This is the same password as an older one, request a password change again
1446 parent.debug('web', 'handleResetPasswordRequest: password rejected, use a different one (2)');
1449 - req.session.loginmode = '6';
1447 + req.session.loginmode = 6;
1448 req.session.messageid = 105; // Password rejected, use a different one.
1449 if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); }
1450 } else {
@@ -1482,26 +1480,25 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1480 // Login successful
1481 parent.debug('web', 'handleResetPasswordRequest: success');
1482 req.session.userid = userid;
1485 - req.session.domainid = domain.id;
1483 req.session.ip = req.clientIp; // Bind this session to the IP address of the request
1487 - completeLoginRequest(req, res, domain, obj.users[userid], userid, req.session.tokenusername, req.session.tokenpassword, direct, loginOptions);
1484 + completeLoginRequest(req, res, domain, obj.users[userid], userid, req.session.tuser, req.session.tpass, direct, loginOptions);
1485 }, 0);
1486 }
1487 }, 0);
1488 } else {
1489 // Failed, error out.
1490 parent.debug('web', 'handleResetPasswordRequest: failed authenticate()');
1494 - delete req.session.u2fchallenge;
1491 + delete req.session.u2f;
1492 delete req.session.loginmode;
1496 - delete req.session.tokenuserid;
1497 - delete req.session.tokenusername;
1498 - delete req.session.tokenpassword;
1493 + delete req.session.tuserid;
1494 + delete req.session.tuser;
1495 + delete req.session.tpass;
1496 delete req.session.resettokenuserid;
1497 delete req.session.resettokenusername;
1498 delete req.session.resettokenpassword;
1502 - delete req.session.tokenemail;
1503 - delete req.session.tokensms;
1504 - delete req.session.tokenpush;
1499 + delete req.session.temail;
1500 + delete req.session.tsms;
1501 + delete req.session.tpush;
1502 delete req.session.messageid;
1503 delete req.session.passhint;
1504 delete req.session.cuserid;
@@ -1524,12 +1521,12 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1521
1522 // Get the email from the body or session.
1523 var email = req.body.email;
1527 - if ((email == null) || (email == '')) { email = req.session.tokenemail; }
1524 + if ((email == null) || (email == '')) { email = req.session.temail; }
1525
1526 // Check the email string format
1527 if (!email || checkEmail(email) == false) {
1528 parent.debug('web', 'handleResetAccountRequest: Invalid email');
1532 - req.session.loginmode = '3';
1529 + req.session.loginmode = 3;
1530 req.session.messageid = 106; // Invalid email.
1531 if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); }
1532 } else {
@@ -1549,7 +1546,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1546 // Check if we have any account that match this email address
1547 if ((err != null) || (docs.length == 0)) {
1548 parent.debug('web', 'handleResetAccountRequest: Account not found');
1552 - req.session.loginmode = '3';
1549 + req.session.loginmode = 3;
1550 req.session.messageid = 1; // If valid, reset mail sent. Instead of "Account not found" (107), we send this hold on message so users can't know if this account exists or not.
1551 if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); }
1552 } else {
@@ -1580,26 +1577,25 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1577 obj.setbadLogin(req);
1578 }
1579 }
1583 - req.session.loginmode = '5';
1584 - delete req.session.tokenemail;
1585 - req.session.tokenemail = email;
1580 + req.session.loginmode = 5;
1581 + req.session.temail = email;
1582 if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); }
1583 }
1584 } else {
1585 // Send email to perform recovery.
1590 - delete req.session.tokenemail;
1586 + delete req.session.temail;
1587 if (domain.mailserver != null) {
1588 domain.mailserver.sendAccountResetMail(domain, user.name, user._id, user.email, obj.getLanguageCodes(req), req.query.key);
1589 if (i == 0) {
1590 parent.debug('web', 'handleResetAccountRequest: Hold on, reset mail sent.');
1595 - req.session.loginmode = '1';
1591 + req.session.loginmode = 1;
1592 req.session.messageid = 1; // If valid, reset mail sent.
1593 if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); }
1594 }
1595 } else {
1596 if (i == 0) {
1597 parent.debug('web', 'handleResetAccountRequest: Unable to sent email.');
1602 - req.session.loginmode = '3';
1598 + req.session.loginmode = 3;
1599 req.session.messageid = 109; // Unable to sent email.
1600 if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); }
1601 }
@@ -1612,14 +1608,14 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1608 domain.mailserver.sendAccountResetMail(domain, user.name, user._id, user.email, obj.getLanguageCodes(req), req.query.key);
1609 if (i == 0) {
1610 parent.debug('web', 'handleResetAccountRequest: Hold on, reset mail sent.');
1615 - req.session.loginmode = '1';
1611 + req.session.loginmode = 1;
1612 req.session.messageid = 1; // If valid, reset mail sent.
1613 if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); }
1614 }
1615 } else {
1616 if (i == 0) {
1617 parent.debug('web', 'handleResetAccountRequest: Unable to sent email.');
1622 - req.session.loginmode = '3';
1618 + req.session.loginmode = 3;
1619 req.session.messageid = 109; // Unable to sent email.
1620 if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); }
1621 }
@@ -1644,7 +1640,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1640
1641 // Get the email from the body or session.
1642 var email = req.body.email;
1647 - if ((email == null) || (email == '')) { email = req.session.tokenemail; }
1643 + if ((email == null) || (email == '')) { email = req.session.temail; }
1644
1645 // Check if this request is for an allows email domain
1646 if ((domain.newaccountemaildomains != null) && Array.isArray(domain.newaccountemaildomains)) {
@@ -1652,7 +1648,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1648 if (typeof req.body.email == 'string') { i = req.body.email.indexOf('@'); }
1649 if (i == -1) {
1650 parent.debug('web', 'handleCreateAccountRequest: unable to create account (1)');
1655 - req.session.loginmode = '7';
1651 + req.session.loginmode = 7;
1652 req.session.messageid = 106; // Invalid email.
1653 if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); }
1654 return;
@@ -1661,7 +1657,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1657 for (var i in domain.newaccountemaildomains) { if (emaildomain == domain.newaccountemaildomains[i].toLowerCase()) { emailok = true; } }
1658 if (emailok == false) {
1659 parent.debug('web', 'handleCreateAccountRequest: unable to create account (2)');
1664 - req.session.loginmode = '7';
1660 + req.session.loginmode = 7;
1661 req.session.messageid = 106; // Invalid email.
1662 if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); }
1663 return;
@@ -1671,7 +1667,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1667 // Check the email string format
1668 if (!email || checkEmail(email) == false) {
1669 parent.debug('web', 'handleCheckAccountEmailRequest: Invalid email');
1674 - req.session.loginmode = '7';
1670 + req.session.loginmode = 7;
1671 req.session.messageid = 106; // Invalid email.
1672 if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); }
1673 } else {
@@ -1699,7 +1695,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1695 // Send the response
1696 req.session.messageid = 2; // Email sent.
1697 }
1702 - req.session.loginmode = '7';
1698 + req.session.loginmode = 7;
1699 delete req.session.cuserid;
1700 if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); }
1701 });
@@ -2044,7 +2040,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2040 if ((loginCookie != null) && (domain.id == loginCookie.domainid)) { user = obj.users[loginCookie.userid]; }
2041 } else {
2042 // Check if the user is logged and we have all required parameters
2047 - if (!req.session || !req.session.userid || !req.body.apassword1 || (req.body.apassword1 != req.body.apassword2) || (req.session.domainid != domain.id)) {
2043 + if (!req.session || !req.session.userid || !req.body.apassword1 || (req.body.apassword1 != req.body.apassword2) || (req.session.userid.split('/')[1] != domain.id)) {
2044 parent.debug('web', 'handleDeleteAccountRequest: required parameters not present.');
2045 if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); }
2046 return;
@@ -2221,7 +2217,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2217 if (req.session.loginToken != null) { res.sendStatus(404); return; } // Do not allow this command when logged in using a login token
2218
2219 // Check if the user is logged and we have all required parameters
2224 - if (!req.session || !req.session.userid || !req.body.apassword0 || !req.body.apassword1 || (req.body.apassword1 != req.body.apassword2) || (req.session.domainid != domain.id)) {
2220 + if (!req.session || !req.session.userid || !req.body.apassword0 || !req.body.apassword1 || (req.body.apassword1 != req.body.apassword2) || (req.session.userid.split('/')[1] != domain.id)) {
2221 parent.debug('web', 'handlePasswordChangeRequest: failed checks (2).');
2222 if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); }
2223 return;
@@ -2353,11 +2349,10 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2349 parent.DispatchEvent(targets, obj, event);
2350
2351 req.session.userid = userid;
2356 - req.session.domainid = domain.id;
2352 } else {
2353 // New users not allowed
2354 parent.debug('web', 'handleStrategyLogin: Can\'t create new accounts');
2360 - req.session.loginmode = '1';
2355 + req.session.loginmode = 1;
2356 req.session.messageid = 100; // Unable to create account.
2357 res.redirect(domain.url + getQueryPortion(req));
2358 return;
@@ -2378,7 +2373,6 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2373 }
2374 parent.debug('web', 'handleStrategyLogin: succesful login: ' + userid);
2375 req.session.userid = userid;
2381 - req.session.domainid = domain.id;
2376 }
2377 }
2378 //res.redirect(domain.url); // This does not handle cookie correctly.
@@ -2422,8 +2416,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2416 if (obj.parent.authlog) { obj.parent.authLog('https', 'Accepted password for ' + req.connection.user + ' from ' + req.clientIp + ' port ' + req.connection.remotePort); }
2417 parent.debug('web', 'handleRootRequest: user/pass in URL auth ok.');
2418 req.session.userid = userid;
2425 - req.session.domainid = domain.id;
2426 - req.session.currentNode = '';
2419 + delete req.session.currentNode;
2420 req.session.ip = req.clientIp; // Bind this session to the IP address of the request
2421 handleRootRequestEx(req, res, domain, direct);
2422 });
@@ -2452,10 +2445,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2445
2446 if (obj.args.nousers == true) {
2447 // If in single user mode, setup things here.
2455 - if (req.session && req.session.loginmode) { delete req.session.loginmode; }
2448 + delete req.session.loginmode;
2449 req.session.userid = 'user/' + domain.id + '/~';
2457 - req.session.domainid = domain.id;
2458 - req.session.currentNode = '';
2450 + delete req.session.currentNode;
2451 req.session.ip = req.clientIp; // Bind this session to the IP address of the request
2452 if (obj.users[req.session.userid] == null) {
2453 // Create the dummy user ~ with impossible password
@@ -2466,10 +2458,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2458 } else if (obj.args.user && obj.users['user/' + domain.id + '/' + obj.args.user.toLowerCase()]) {
2459 // If a default user is active, setup the session here.
2460 parent.debug('web', 'handleRootRequestEx: auth using default user.');
2469 - if (req.session && req.session.loginmode) { delete req.session.loginmode; }
2461 + delete req.session.loginmode;
2462 req.session.userid = 'user/' + domain.id + '/' + obj.args.user.toLowerCase();
2471 - req.session.domainid = domain.id;
2472 - req.session.currentNode = '';
2463 + delete req.session.currentNode;
2464 req.session.ip = req.clientIp; // Bind this session to the IP address of the request
2465 } else if (req.query.login && (obj.parent.loginCookieEncryptionKey != null)) {
2466 var loginCookie = obj.parent.decodeCookie(req.query.login, obj.parent.loginCookieEncryptionKey, 60); // 60 minute timeout
@@ -2477,10 +2468,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2468 if ((loginCookie != null) && (loginCookie.a == 3) && (loginCookie.u != null) && (loginCookie.u.split('/')[1] == domain.id)) {
2469 // If a login cookie was provided, setup the session here.
2470 parent.debug('web', 'handleRootRequestEx: cookie auth ok.');
2480 - if (req.session && req.session.loginmode) { delete req.session.loginmode; }
2471 + delete req.session.loginmode;
2472 req.session.userid = loginCookie.u;
2482 - req.session.domainid = domain.id;
2483 - req.session.currentNode = '';
2473 + delete req.session.currentNode;
2474 req.session.ip = req.clientIp; // Bind this session to the IP address of the request
2475 } else {
2476 parent.debug('web', 'handleRootRequestEx: cookie auth failed.');
@@ -2496,8 +2486,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2486 req.session.userid = 'user/' + domain.id + '/' + req.connection.user.toLowerCase();
2487 req.session.usersid = req.connection.userSid;
2488 req.session.usersGroups = req.connection.userGroups;
2499 - req.session.domainid = domain.id;
2500 - req.session.currentNode = '';
2489 + delete req.session.currentNode;
2490 req.session.ip = req.clientIp; // Bind this session to the IP address of the request
2491
2492 // Check if this user exists, create it if not.
@@ -2571,7 +2560,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2560 }
2561
2562 const xdbGetFunc = function dbGetFunc(err, states) {
2574 - if (dbGetFunc.req.session.domainid != domain.id) { // Check if the session is for the correct domain
2563 + if (dbGetFunc.req.session.userid.split('/')[1] != domain.id) { // Check if the session is for the correct domain
2564 parent.debug('web', 'handleRootRequestEx: incorrect domain.');
2565 dbGetFunc.req.session = null;
2566 dbGetFunc.res.redirect(domain.url + getQueryPortion(dbGetFunc.req)); // BAD***
@@ -2583,7 +2572,6 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2572 // Locked account
2573 parent.debug('web', 'handleRootRequestEx: locked account.');
2574 delete dbGetFunc.req.session.userid;
2586 - delete dbGetFunc.req.session.domainid;
2575 delete dbGetFunc.req.session.currentNode;
2576 delete dbGetFunc.req.session.passhint;
2577 delete dbGetFunc.req.session.cuserid;
@@ -2674,7 +2662,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2662 var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified
2663
2664 // Clean up the U2F challenge if needed
2677 - if (dbGetFunc.req.session.u2fchallenge) { delete dbGetFunc.req.session.u2fchallenge; };
2665 + if (dbGetFunc.req.session.u2f) { delete dbGetFunc.req.session.u2f; };
2666
2667 // Intel AMT Scanning options
2668 var amtscanoptions = '';
@@ -2748,8 +2736,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2736 // Send back the login application
2737 // If this is a 2 factor auth request, look for a hardware key challenge.
2738 // Normal login 2 factor request
2751 - if (req.session && (req.session.loginmode == '4') && (req.session.tokenuserid)) {
2752 - var user = obj.users[req.session.tokenuserid];
2739 + if (req.session && (req.session.loginmode == 4) && (req.session.tuserid)) {
2740 + var user = obj.users[req.session.tuserid];
2741 if (user != null) {
2742 parent.debug('web', 'handleRootRequestEx: sending 2FA challenge.');
2743 getHardwareKeyChallenge(req, domain, user, function (hwchallenge) { handleRootRequestLogin(req, res, domain, hwchallenge, passRequirements); });
@@ -2757,8 +2745,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2745 }
2746 }
2747 // Password recovery 2 factor request
2760 - if (req.session && (req.session.loginmode == '5') && (req.session.tokenemail)) {
2761 - obj.db.GetUserWithVerifiedEmail(domain.id, req.session.tokenemail, function (err, docs) {
2748 + if (req.session && (req.session.loginmode == 5) && (req.session.temail)) {
2749 + obj.db.GetUserWithVerifiedEmail(domain.id, req.session.temail, function (err, docs) {
2750 if ((err != null) || (docs.length == 0)) {
2751 parent.debug('web', 'handleRootRequestEx: password recover 2FA fail.');
2752 req.session = null;
@@ -2787,14 +2775,14 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2775 if ((parent.config != null) && (parent.config.settings != null) && ((parent.config.settings.allowframing == true) || (typeof parent.config.settings.allowframing == 'string'))) { features += 32; } // Allow site within iframe
2776 if (domain.usernameisemail) { features += 0x00200000; } // Username is email address
2777 var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified
2790 - var loginmode = '';
2778 + var loginmode = 0;
2779 if (req.session) { loginmode = req.session.loginmode; delete req.session.loginmode; } // Clear this state, if the user hits refresh, we want to go back to the login page.
2780
2781 // Format an error message if needed
2782 var passhint = null, msgid = 0;
2783 if (req.session != null) {
2784 msgid = req.session.messageid;
2797 - if ((msgid == 5) || (loginmode == '7') || ((domain.passwordrequirements != null) && (domain.passwordrequirements.hint === true))) { passhint = EscapeHtml(req.session.passhint); }
2785 + if ((msgid == 5) || (loginmode == 7) || ((domain.passwordrequirements != null) && (domain.passwordrequirements.hint === true))) { passhint = EscapeHtml(req.session.passhint); }
2786 delete req.session.messageid;
2787 delete req.session.passhint;
2788 }
@@ -2807,14 +2795,14 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2795
2796 // Encrypt the hardware key challenge state if needed
2797 var hwstate = null;
2810 - if (hardwareKeyChallenge) { hwstate = obj.parent.encodeCookie({ u: req.session.tokenusername, p: req.session.tokenpassword, c: req.session.u2fchallenge }, obj.parent.loginCookieEncryptionKey) }
2798 + if (hardwareKeyChallenge) { hwstate = obj.parent.encodeCookie({ u: req.session.tuser, p: req.session.tpass, c: req.session.u2f }, obj.parent.loginCookieEncryptionKey) }
2799
2800 // Check if we can use OTP tokens with email. We can't use email for 2FA password recovery (loginmode 5).
2813 - var otpemail = (loginmode != 5) && (domain.mailserver != null) && (req.session != null) && ((req.session.tokenemail == true) || (typeof req.session.tokenemail == 'string'));
2801 + var otpemail = (loginmode != 5) && (domain.mailserver != null) && (req.session != null) && ((req.session.temail === 1) || (typeof req.session.temail == 'string'));
2802 if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.email2factor == false)) { otpemail = false; }
2815 - var otpsms = (parent.smsserver != null) && (req.session != null) && (req.session.tokensms == true);
2803 + var otpsms = (parent.smsserver != null) && (req.session != null) && (req.session.tsms === 1);
2804 if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.sms2factor == false)) { otpsms = false; }
2817 - var otppush = (parent.firebase != null) && (req.session != null) && (req.session.tokenpush == true);
2805 + var otppush = (parent.firebase != null) && (req.session != null) && (req.session.tpush === 1);
2806 if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.push2factor == false)) { otppush = false; }
2807
2808 // See if we support two-factor trusted cookies
@@ -2882,7 +2870,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2870 case 'tokenlogin': {
2871 if (req.body.hwstate) {
2872 var cookie = obj.parent.decodeCookie(req.body.hwstate, obj.parent.loginCookieEncryptionKey, 10);
2885 - if (cookie != null) { req.session.tokenusername = cookie.u; req.session.tokenpassword = cookie.p; req.session.u2fchallenge = cookie.c; }
2873 + if (cookie != null) { req.session.tuser = cookie.u; req.session.tpass = cookie.p; req.session.u2f = cookie.c; }
2874 }
2875 handleLoginRequest(req, res, true); break;
2876 }
@@ -2891,7 +2879,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2879 var cookie = obj.parent.decodeCookie(req.body.hwstate, obj.parent.loginCookieEncryptionKey, 1);
2880 if ((cookie != null) && (typeof cookie.u == 'string') && (cookie.d == domain.id) && (cookie.a == 'pushAuth')) {
2881 // Push authentication is a success, login the user
2894 - req.session = { userid: cookie.u, domainid: cookie.d }
2882 + req.session = { userid: cookie.u };
2883
2884 // Check if we need to remember this device
2885 if ((req.body.remembertoken === 'on') && ((domain.twofactorcookiedurationdays == null) || (domain.twofactorcookiedurationdays > 0))) {
@@ -2944,7 +2932,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2932 parent.debug('web', 'handleXTermRequest: sending xterm');
2933 res.set({ 'Cache-Control': 'no-store' });
2934 if (req.session && req.session.userid) {
2947 - if (req.session.domainid != domain.id) { res.redirect(domain.url + getQueryPortion(req)); return; } // Check if the session is for the correct domain
2935 + if (req.session.userid.split('/')[1] != domain.id) { res.redirect(domain.url + getQueryPortion(req)); return; } // Check if the session is for the correct domain
2936 var user = obj.users[req.session.userid];
2937 if ((user == null) || (req.query.nodeid == null)) { res.redirect(domain.url + getQueryPortion(req)); return; } // Check if the user exists
2938
@@ -2979,7 +2967,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2967 // Send the terms from the database
2968 res.set({ 'Cache-Control': 'no-store' });
2969 if (req.session && req.session.userid) {
2982 - if (req.session.domainid != domain.id) { req.session = null; res.redirect(domain.url + getQueryPortion(req)); return; } // Check if the session is for the correct domain
2970 + if (req.session.userid.split('/')[1] != domain.id) { req.session = null; res.redirect(domain.url + getQueryPortion(req)); return; } // Check if the session is for the correct domain
2971 var user = obj.users[req.session.userid];
2972 var logoutcontrols = { name: user.name };
2973 var extras = (req.query.key != null) ? ('&key=' + req.query.key) : '';
@@ -2998,7 +2986,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2986 // Send the terms from terms.txt
2987 res.set({ 'Cache-Control': 'no-store' });
2988 if (req.session && req.session.userid) {
3001 - if (req.session.domainid != domain.id) { req.session = null; res.redirect(domain.url + getQueryPortion(req)); return; } // Check if the session is for the correct domain
2989 + if (req.session.userid.split('/')[1] != domain.id) { req.session = null; res.redirect(domain.url + getQueryPortion(req)); return; } // Check if the session is for the correct domain
2990 var user = obj.users[req.session.userid];
2991 var logoutcontrols = { name: user.name };
2992 var extras = (req.query.key != null) ? ('&key=' + req.query.key) : '';
@@ -3013,7 +3001,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3001 parent.debug('web', 'handleTermsRequest: sending default terms');
3002 res.set({ 'Cache-Control': 'no-store' });
3003 if (req.session && req.session.userid) {
3016 - if (req.session.domainid != domain.id) { req.session = null; res.redirect(domain.url + getQueryPortion(req)); return; } // Check if the session is for the correct domain
3004 + if (req.session.userid.split('/')[1] != domain.id) { req.session = null; res.redirect(domain.url + getQueryPortion(req)); return; } // Check if the session is for the correct domain
3005 var user = obj.users[req.session.userid];
3006 var logoutcontrols = { name: user.name };
3007 var extras = (req.query.key != null) ? ('&key=' + req.query.key) : '';
@@ -5286,6 +5274,20 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
5274
5275 // Add HTTP security headers to all responses
5276 obj.app.use(function (req, res, next) {
5277 +
5278 + // Remove legacy values from the session to keep the session as small as possible
5279 + delete req.session.domainid;
5280 + delete req.session.u2fchallenge
5281 + delete req.session.nowInMinutes;
5282 + delete req.session.tokenuserid;
5283 + delete req.session.tokenusername;
5284 + delete req.session.tokenpassword;
5285 + delete req.session.tokenemail;
5286 + delete req.session.tokensms;
5287 + delete req.session.tokenpush;
5288 + delete req.session.tusername;
5289 + delete req.session.tpassword;
5290 +
5291 // Useful for debugging reverse proxy issues
5292 parent.debug('httpheaders', req.method, req.url, req.headers);
5293
@@ -5378,7 +5380,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
5380 if ((req.session.ip != null) && (req.clientIp != null) && (req.session.ip != req.clientIp)) { req.session = {}; }
5381
5382 // Extend the session time by forcing a change to the session every minute.
5381 - if (req.session.userid != null) { req.session.nowInMinutes = Math.floor(Date.now() / 60e3); } else { delete req.session.nowInMinutes; }
5383 + if (req.session.userid != null) { req.session.t = Math.floor(Date.now() / 60e3); } else { delete req.session.t; }
5384
5385 // Debugging code, this will stop the agent from crashing if two responses are made to the same request.
5386 const render = res.render;
@@ -6373,7 +6375,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
6375 // A default user is active
6376 func(ws, req, domain, obj.users['user/' + domain.id + '/' + obj.args.user.toLowerCase()]);
6377 return;
6376 - } else if (req.session && (req.session.userid != null) && (req.session.domainid == domain.id) && (obj.users[req.session.userid])) {
6378 + } else if (req.session && (req.session.userid != null) && (req.session.userid.split('/')[1] == domain.id) && (obj.users[req.session.userid])) {
6379 // This user is logged in using the ExpressJS session
6380 func(ws, req, domain, obj.users[req.session.userid]);
6381 return;