mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2024-09-11 08:55:32 +03:00
Password reset improvements.
This commit is contained in:
parent
005921cf7b
commit
650e0bf07c
@ -233,7 +233,7 @@ module.exports.CreateMeshMail = function (parent) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Send account reset mail
|
// Send account reset mail
|
||||||
obj.sendAccountResetMail = function (domain, username, email, language, loginkey) {
|
obj.sendAccountResetMail = function (domain, username, userid, email, language, loginkey) {
|
||||||
obj.checkEmail(email, function (checked) {
|
obj.checkEmail(email, function (checked) {
|
||||||
if (checked) {
|
if (checked) {
|
||||||
parent.debug('email', "Sending account password reset to " + email);
|
parent.debug('email', "Sending account password reset to " + email);
|
||||||
@ -252,7 +252,7 @@ module.exports.CreateMeshMail = function (parent) {
|
|||||||
// Set all the options.
|
// Set all the options.
|
||||||
var options = { username: username, email: email, servername: domain.title ? domain.title : 'MeshCentral' };
|
var options = { username: username, email: email, servername: domain.title ? domain.title : 'MeshCentral' };
|
||||||
if (loginkey != null) { options.urlargs1 = '?key=' + loginkey; options.urlargs2 = '&key=' + loginkey; } else { options.urlargs1 = ''; options.urlargs2 = ''; }
|
if (loginkey != null) { options.urlargs1 = '?key=' + loginkey; options.urlargs2 = '&key=' + loginkey; } else { options.urlargs1 = ''; options.urlargs2 = ''; }
|
||||||
options.cookie = obj.parent.encodeCookie({ u: domain.id + '/' + username, e: email, a: 2 }, obj.mailCookieEncryptionKey);
|
options.cookie = obj.parent.encodeCookie({ u: userid, e: email, a: 2 }, obj.mailCookieEncryptionKey);
|
||||||
|
|
||||||
// Send the email
|
// Send the email
|
||||||
obj.pendingMails.push({ to: email, from: parent.config.smtp.from, subject: mailReplacements(template.htmlSubject, domain, options), text: mailReplacements(template.txt, domain, options), html: mailReplacements(template.html, domain, options) });
|
obj.pendingMails.push({ to: email, from: parent.config.smtp.from, subject: mailReplacements(template.htmlSubject, domain, options), text: mailReplacements(template.txt, domain, options), html: mailReplacements(template.html, domain, options) });
|
||||||
|
@ -44,7 +44,9 @@
|
|||||||
"express": "^4.17.0",
|
"express": "^4.17.0",
|
||||||
"express-handlebars": "^3.1.0",
|
"express-handlebars": "^3.1.0",
|
||||||
"express-ws": "^4.0.0",
|
"express-ws": "^4.0.0",
|
||||||
|
"html-minifier": "^4.0.0",
|
||||||
"ipcheck": "^0.1.0",
|
"ipcheck": "^0.1.0",
|
||||||
|
"minify-js": "0.0.4",
|
||||||
"minimist": "^1.2.0",
|
"minimist": "^1.2.0",
|
||||||
"multiparty": "^4.2.1",
|
"multiparty": "^4.2.1",
|
||||||
"nedb": "^1.8.0",
|
"nedb": "^1.8.0",
|
||||||
|
2
public/scripts/amt-wsman-0.2.0-min.js
vendored
2
public/scripts/amt-wsman-0.2.0-min.js
vendored
File diff suppressed because one or more lines are too long
@ -68,6 +68,7 @@ var minifyMeshCentralSourceFiles = [
|
|||||||
"../views/terms-mobile.handlebars",
|
"../views/terms-mobile.handlebars",
|
||||||
"../views/xterm.handlebars",
|
"../views/xterm.handlebars",
|
||||||
"../views/message.handlebars",
|
"../views/message.handlebars",
|
||||||
|
"../views/message2.handlebars",
|
||||||
"../views/messenger.handlebars",
|
"../views/messenger.handlebars",
|
||||||
"../views/player.handlebars",
|
"../views/player.handlebars",
|
||||||
"../views/desktop.handlebars",
|
"../views/desktop.handlebars",
|
||||||
|
@ -7733,7 +7733,9 @@
|
|||||||
"zh-chs": "单击此处重置您的帐户密码。",
|
"zh-chs": "单击此处重置您的帐户密码。",
|
||||||
"zh-cht": "單擊此處重置你的帳戶密碼。",
|
"zh-cht": "單擊此處重置你的帳戶密碼。",
|
||||||
"xloc": [
|
"xloc": [
|
||||||
"account-reset.html->2->5->1"
|
"account-reset.html->2->5->1",
|
||||||
|
"message.handlebars->3->19",
|
||||||
|
"message2.handlebars->5->19"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -16674,8 +16676,8 @@
|
|||||||
"zh-chs": "进入登录页面",
|
"zh-chs": "进入登录页面",
|
||||||
"zh-cht": "進入登入頁面",
|
"zh-cht": "進入登入頁面",
|
||||||
"xloc": [
|
"xloc": [
|
||||||
"message.handlebars->3->19",
|
"message.handlebars->3->20",
|
||||||
"message2.handlebars->5->19"
|
"message2.handlebars->5->20"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -42116,7 +42118,7 @@
|
|||||||
"ru": "macOS ARM (64bit)",
|
"ru": "macOS ARM (64bit)",
|
||||||
"tr": "macOS ARM (64bit)",
|
"tr": "macOS ARM (64bit)",
|
||||||
"zh-chs": "macOS ARM (64位)",
|
"zh-chs": "macOS ARM (64位)",
|
||||||
"zh-cht": "macOS ARM (64位)"
|
"zh-cht": "macOS ARM (64位)",
|
||||||
"xloc": [
|
"xloc": [
|
||||||
"default.handlebars->29->815"
|
"default.handlebars->29->815"
|
||||||
]
|
]
|
||||||
@ -42125,7 +42127,6 @@
|
|||||||
"en": "macOS x86 (64bit)",
|
"en": "macOS x86 (64bit)",
|
||||||
"cs": "macOS x86 (64bit)",
|
"cs": "macOS x86 (64bit)",
|
||||||
"de": "macOS x86 (64bit)",
|
"de": "macOS x86 (64bit)",
|
||||||
"en": "macOS x86 (64bit)",
|
|
||||||
"es": "macOS x86 (64bit)",
|
"es": "macOS x86 (64bit)",
|
||||||
"fi": "macOS x86 (64-bittinen)",
|
"fi": "macOS x86 (64-bittinen)",
|
||||||
"fr": "macOS x86 (64bit)",
|
"fr": "macOS x86 (64bit)",
|
||||||
@ -42137,7 +42138,7 @@
|
|||||||
"ru": "macOS x86 (64bit)",
|
"ru": "macOS x86 (64bit)",
|
||||||
"tr": "macOS x86 (64bit)",
|
"tr": "macOS x86 (64bit)",
|
||||||
"zh-chs": "macOS x86 (64位)",
|
"zh-chs": "macOS x86 (64位)",
|
||||||
"zh-cht": "macOS x86 (64位)"
|
"zh-cht": "macOS x86 (64位)",
|
||||||
"xloc": [
|
"xloc": [
|
||||||
"default.handlebars->29->814"
|
"default.handlebars->29->814"
|
||||||
]
|
]
|
||||||
@ -42157,7 +42158,7 @@
|
|||||||
"ru": "macOS x86-32bit",
|
"ru": "macOS x86-32bit",
|
||||||
"tr": "macOS x86-32bit",
|
"tr": "macOS x86-32bit",
|
||||||
"zh-chs": "macOS x86-32位",
|
"zh-chs": "macOS x86-32位",
|
||||||
"zh-cht": "macOS x86-32位"
|
"zh-cht": "macOS x86-32位",
|
||||||
"xloc": [
|
"xloc": [
|
||||||
"default.handlebars->29->24"
|
"default.handlebars->29->24"
|
||||||
]
|
]
|
||||||
@ -42177,7 +42178,7 @@
|
|||||||
"ru": "macOS x86-64bit",
|
"ru": "macOS x86-64bit",
|
||||||
"tr": "macOS x86-64bit",
|
"tr": "macOS x86-64bit",
|
||||||
"zh-chs": "macOS x86-64位",
|
"zh-chs": "macOS x86-64位",
|
||||||
"zh-cht": "macOS x86-64位"
|
"zh-cht": "macOS x86-64位",
|
||||||
"xloc": [
|
"xloc": [
|
||||||
"default.handlebars->29->29"
|
"default.handlebars->29->29"
|
||||||
]
|
]
|
||||||
@ -43532,4 +43533,4 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
@ -77,10 +77,11 @@
|
|||||||
case 11: { msg = "Sharing link not valid yet."; break; }
|
case 11: { msg = "Sharing link not valid yet."; break; }
|
||||||
case 12: { msg = "Sharing link is expired."; break; }
|
case 12: { msg = "Sharing link is expired."; break; }
|
||||||
case 13: { msg = "If you are an administrator, [login here].".replace('[', '<a href=login?admin=1>').replace(']', '</a>'); break; }
|
case 13: { msg = "If you are an administrator, [login here].".replace('[', '<a href=login?admin=1>').replace(']', '</a>'); break; }
|
||||||
|
case 14: { msg = '<a href=' + window.location.href + '&confirm=1>' + "Click here to reset your account password." + '</a>'; break; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add login page link
|
// Add login page link
|
||||||
if ((msgid != 11) && (msgid != 12) && (msgid != 13)) { msg += ' <a href="' + domainurl + (urlargs.key ? ('?key=' + urlargs.key) : '') + '">' + "Go to login page" + '</a>.' }
|
if ((msgid != 11) && (msgid != 12) && (msgid != 13) && (msgid != 14)) { msg += ' <a href="' + domainurl + (urlargs.key ? ('?key=' + urlargs.key) : '') + '">' + "Go to login page" + '</a>.' }
|
||||||
QH('mainMessage', msg);
|
QH('mainMessage', msg);
|
||||||
|
|
||||||
function format(format) { var args = Array.prototype.slice.call(arguments, 1); return format.replace(/{(\d+)}/g, function (match, number) { return typeof args[number] != 'undefined' ? args[number] : match; }); };
|
function format(format) { var args = Array.prototype.slice.call(arguments, 1); return format.replace(/{(\d+)}/g, function (match, number) { return typeof args[number] != 'undefined' ? args[number] : match; }); };
|
||||||
|
@ -78,10 +78,11 @@
|
|||||||
case 11: { msg = "Sharing link not valid yet."; break; }
|
case 11: { msg = "Sharing link not valid yet."; break; }
|
||||||
case 12: { msg = "Sharing link is expired."; break; }
|
case 12: { msg = "Sharing link is expired."; break; }
|
||||||
case 13: { msg = "If you are an administrator, [login here].".replace('[', '<a href=?admin=1>').replace(']', '</a>'); break; }
|
case 13: { msg = "If you are an administrator, [login here].".replace('[', '<a href=?admin=1>').replace(']', '</a>'); break; }
|
||||||
|
case 14: { msg = '<a href=' + window.location.href + '&confirm=1>' + "Click here to reset your account password." + '</a>'; break; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add login page link
|
// Add login page link
|
||||||
if ((msgid != 11) && (msgid != 12) && (msgid != 13)) { msg += ' <a href="' + domainurl + (urlargs.key ? ('?key=' + urlargs.key) : '') + '">' + "Go to login page" + '</a>.' }
|
if ((msgid != 11) && (msgid != 12) && (msgid != 13) && (msgid != 14)) { msg += ' <a href="' + domainurl + (urlargs.key ? ('?key=' + urlargs.key) : '') + '">' + "Go to login page" + '</a>.' }
|
||||||
QH('mainMessage', msg);
|
QH('mainMessage', msg);
|
||||||
|
|
||||||
function format(format) { var args = Array.prototype.slice.call(arguments, 1); return format.replace(/{(\d+)}/g, function (match, number) { return typeof args[number] != 'undefined' ? args[number] : match; }); };
|
function format(format) { var args = Array.prototype.slice.call(arguments, 1); return format.replace(/{(\d+)}/g, function (match, number) { return typeof args[number] != 'undefined' ? args[number] : match; }); };
|
||||||
|
102
webserver.js
102
webserver.js
@ -942,7 +942,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
req.session.messageid = 108; // Invalid token, try again.
|
req.session.messageid = 108; // Invalid token, try again.
|
||||||
if (obj.parent.authlog) { obj.parent.authLog('https', 'Failed 2FA for ' + xusername + ' from ' + cleanRemoteAddr(req.clientIp) + ' port ' + req.port); }
|
if (obj.parent.authlog) { obj.parent.authLog('https', 'Failed 2FA for ' + xusername + ' from ' + cleanRemoteAddr(req.clientIp) + ' port ' + req.port); }
|
||||||
parent.debug('web', 'handleLoginRequest: invalid 2FA token');
|
parent.debug('web', 'handleLoginRequest: invalid 2FA token');
|
||||||
obj.parent.DispatchEvent(['*', 'server-users', 'user/' + domain.id + '/' + user.name], obj, { action: 'authfail', username: user.name, userid: 'user/' + domain.id + '/' + user.name, domain: domain.id, msg: 'User login attempt with incorrect 2nd factor from ' + req.clientIp });
|
obj.parent.DispatchEvent(['*', 'server-users', user._id], obj, { action: 'authfail', username: user.name, userid: user._id, domain: domain.id, msg: 'User login attempt with incorrect 2nd factor from ' + req.clientIp });
|
||||||
obj.setbadLogin(req);
|
obj.setbadLogin(req);
|
||||||
} else {
|
} else {
|
||||||
parent.debug('web', 'handleLoginRequest: 2FA token required');
|
parent.debug('web', 'handleLoginRequest: 2FA token required');
|
||||||
@ -1389,6 +1389,19 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); }
|
if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); }
|
||||||
} else {
|
} else {
|
||||||
obj.db.GetUserWithVerifiedEmail(domain.id, email, function (err, docs) {
|
obj.db.GetUserWithVerifiedEmail(domain.id, email, function (err, docs) {
|
||||||
|
// Remove all accounts that start with ~ since they are special accounts.
|
||||||
|
var cleanDocs = [];
|
||||||
|
if ((err == null) && (docs.length > 0)) {
|
||||||
|
for (var i in docs) {
|
||||||
|
const user = docs[i];
|
||||||
|
const locked = ((user.siteadmin != null) && (user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 1024) != 0)); // No password recovery for locked accounts
|
||||||
|
const specialAccount = (user._id.split('/')[2].startsWith('~')); // No password recovery for special accounts
|
||||||
|
if ((specialAccount == false) && (locked == false)) { cleanDocs.push(user); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
docs = cleanDocs;
|
||||||
|
|
||||||
|
// Check if we have any account that match this email address
|
||||||
if ((err != null) || (docs.length == 0)) {
|
if ((err != null) || (docs.length == 0)) {
|
||||||
parent.debug('web', 'handleResetAccountRequest: Account not found');
|
parent.debug('web', 'handleResetAccountRequest: Account not found');
|
||||||
req.session.loginmode = '3';
|
req.session.loginmode = '3';
|
||||||
@ -1407,11 +1420,22 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
// 2-step auth is required, but the token is not present or not valid.
|
// 2-step auth is required, but the token is not present or not valid.
|
||||||
parent.debug('web', 'handleResetAccountRequest: Invalid 2FA token, try again');
|
parent.debug('web', 'handleResetAccountRequest: Invalid 2FA token, try again');
|
||||||
if ((req.body.token != null) || (req.body.hwtoken != null)) {
|
if ((req.body.token != null) || (req.body.hwtoken != null)) {
|
||||||
req.session.messageid = 108; // Invalid token, try again.
|
var sms2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)) && (parent.smsserver != null) && (user.phone != null));
|
||||||
obj.parent.DispatchEvent(['*', 'server-users', 'user/' + domain.id + '/' + user.name], obj, { action: 'authfail', username: user.name, userid: 'user/' + domain.id + '/' + user.name, domain: domain.id, msg: 'User login attempt with incorrect 2nd factor from ' + req.clientIp });
|
if ((req.body.hwtoken == '**sms**') && sms2fa) {
|
||||||
obj.setbadLogin(req);
|
// Cause a token to be sent to the user's phone number
|
||||||
|
user.otpsms = { k: obj.common.zeroPad(getRandomSixDigitInteger(), 6), d: Date.now() };
|
||||||
|
obj.db.SetUser(user);
|
||||||
|
parent.debug('web', 'Sending 2FA SMS for password recovery to: ' + user.phone);
|
||||||
|
parent.smsserver.sendToken(domain, user.phone, user.otpsms.k, obj.getLanguageCodes(req));
|
||||||
|
req.session.messageid = 4; // SMS sent.
|
||||||
|
} else {
|
||||||
|
req.session.messageid = 108; // Invalid token, try again.
|
||||||
|
obj.parent.DispatchEvent(['*', 'server-users', user._id], obj, { action: 'authfail', username: user.name, userid: user._id, domain: domain.id, msg: 'User login attempt with incorrect 2nd factor from ' + req.clientIp });
|
||||||
|
obj.setbadLogin(req);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
req.session.loginmode = '5';
|
req.session.loginmode = '5';
|
||||||
|
delete req.session.tokenemail;
|
||||||
req.session.tokenemail = email;
|
req.session.tokenemail = email;
|
||||||
if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); }
|
if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); }
|
||||||
}
|
}
|
||||||
@ -1419,7 +1443,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
// Send email to perform recovery.
|
// Send email to perform recovery.
|
||||||
delete req.session.tokenemail;
|
delete req.session.tokenemail;
|
||||||
if (obj.parent.mailserver != null) {
|
if (obj.parent.mailserver != null) {
|
||||||
obj.parent.mailserver.sendAccountResetMail(domain, user.name, user.email, obj.getLanguageCodes(req), req.query.key);
|
obj.parent.mailserver.sendAccountResetMail(domain, user.name, user._id, user.email, obj.getLanguageCodes(req), req.query.key);
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
parent.debug('web', 'handleResetAccountRequest: Hold on, reset mail sent.');
|
parent.debug('web', 'handleResetAccountRequest: Hold on, reset mail sent.');
|
||||||
req.session.loginmode = '1';
|
req.session.loginmode = '1';
|
||||||
@ -1439,7 +1463,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
} else {
|
} else {
|
||||||
// No second factor, send email to perform recovery.
|
// No second factor, send email to perform recovery.
|
||||||
if (obj.parent.mailserver != null) {
|
if (obj.parent.mailserver != null) {
|
||||||
obj.parent.mailserver.sendAccountResetMail(domain, user.name, user.email, obj.getLanguageCodes(req), req.query.key);
|
obj.parent.mailserver.sendAccountResetMail(domain, user.name, user._id, user.email, obj.getLanguageCodes(req), req.query.key);
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
parent.debug('web', 'handleResetAccountRequest: Hold on, reset mail sent.');
|
parent.debug('web', 'handleResetAccountRequest: Hold on, reset mail sent.');
|
||||||
req.session.loginmode = '1';
|
req.session.loginmode = '1';
|
||||||
@ -1544,13 +1568,13 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
|
|
||||||
if (req.query.c != null) {
|
if (req.query.c != null) {
|
||||||
var cookie = obj.parent.decodeCookie(req.query.c, obj.parent.mailserver.mailCookieEncryptionKey, 30);
|
var cookie = obj.parent.decodeCookie(req.query.c, obj.parent.mailserver.mailCookieEncryptionKey, 30);
|
||||||
if ((cookie != null) && (cookie.u != null) && (cookie.e != null)) {
|
if ((cookie != null) && (cookie.u != null) && (cookie.u.startsWith('user/')) && (cookie.e != null)) {
|
||||||
var idsplit = cookie.u.split('/');
|
var idsplit = cookie.u.split('/');
|
||||||
if ((idsplit.length != 2) || (idsplit[0] != domain.id)) {
|
if ((idsplit.length != 3) || (idsplit[1] != domain.id)) {
|
||||||
parent.debug('web', 'handleCheckMailRequest: Invalid domain.');
|
parent.debug('web', 'handleCheckMailRequest: Invalid domain.');
|
||||||
render(req, res, getRenderPage((domain.sitestyle == 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 1, msgid: 1, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain));
|
render(req, res, getRenderPage((domain.sitestyle == 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 1, msgid: 1, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain));
|
||||||
} else {
|
} else {
|
||||||
obj.db.Get('user/' + cookie.u.toLowerCase(), function (err, docs) {
|
obj.db.Get(cookie.u, function (err, docs) {
|
||||||
if (docs.length == 0) {
|
if (docs.length == 0) {
|
||||||
parent.debug('web', 'handleCheckMailRequest: Invalid username.');
|
parent.debug('web', 'handleCheckMailRequest: Invalid username.');
|
||||||
render(req, res, getRenderPage((domain.sitestyle == 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 1, msgid: 2, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27'), arg1: encodeURIComponent(idsplit[1]).replace(/'/g, '%27') }, req, domain));
|
render(req, res, getRenderPage((domain.sitestyle == 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 1, msgid: 2, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27'), arg1: encodeURIComponent(idsplit[1]).replace(/'/g, '%27') }, req, domain));
|
||||||
@ -1600,36 +1624,40 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
parent.debug('web', 'handleCheckMailRequest: email not verified.');
|
parent.debug('web', 'handleCheckMailRequest: email not verified.');
|
||||||
render(req, res, getRenderPage((domain.sitestyle == 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 1, msgid: 7, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27'), arg1: EscapeHtml(user.email), arg2: EscapeHtml(user.name) }, req, domain));
|
render(req, res, getRenderPage((domain.sitestyle == 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 1, msgid: 7, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27'), arg1: EscapeHtml(user.email), arg2: EscapeHtml(user.name) }, req, domain));
|
||||||
} else {
|
} else {
|
||||||
// Set a temporary password
|
if (req.query.confirm == 1) {
|
||||||
obj.crypto.randomBytes(16, function (err, buf) {
|
// Set a temporary password
|
||||||
var newpass = buf.toString('base64').split('=').join('').split('/').join('');
|
obj.crypto.randomBytes(16, function (err, buf) {
|
||||||
require('./pass').hash(newpass, function (err, salt, hash, tag) {
|
var newpass = buf.toString('base64').split('=').join('').split('/').join('').split('+').join('');
|
||||||
var userinfo = null;
|
require('./pass').hash(newpass, function (err, salt, hash, tag) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
|
|
||||||
// Change the password
|
// Change the password
|
||||||
userinfo = obj.users[user._id];
|
var userinfo = obj.users[user._id];
|
||||||
userinfo.salt = salt;
|
userinfo.salt = salt;
|
||||||
userinfo.hash = hash;
|
userinfo.hash = hash;
|
||||||
delete userinfo.passtype;
|
delete userinfo.passtype;
|
||||||
userinfo.passchange = Math.floor(Date.now() / 1000);
|
userinfo.passchange = Math.floor(Date.now() / 1000);
|
||||||
delete userinfo.passhint;
|
delete userinfo.passhint;
|
||||||
//delete userinfo.otpsecret; // Currently a email password reset will turn off 2-step login.
|
obj.db.SetUser(userinfo);
|
||||||
obj.db.SetUser(userinfo);
|
|
||||||
|
|
||||||
// Event the change
|
// Event the change
|
||||||
var event = { etype: 'user', userid: user._id, username: userinfo.name, account: obj.CloneSafeUser(userinfo), action: 'accountchange', msg: 'Password reset for user ' + EscapeHtml(user.name), domain: domain.id };
|
var event = { etype: 'user', userid: user._id, username: userinfo.name, account: obj.CloneSafeUser(userinfo), action: 'accountchange', msg: 'Password reset for user ' + EscapeHtml(user.name), domain: domain.id };
|
||||||
if (obj.db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the user. Another event will come.
|
if (obj.db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the user. Another event will come.
|
||||||
obj.parent.DispatchEvent(['*', 'server-users', user._id], obj, event);
|
obj.parent.DispatchEvent(['*', 'server-users', user._id], obj, event);
|
||||||
|
|
||||||
// Send the new password
|
// Send the new password
|
||||||
render(req, res, getRenderPage((domain.sitestyle == 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 1, msgid: 8, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27'), arg1: EscapeHtml(user.name), arg2: EscapeHtml(newpass) }, req, domain));
|
render(req, res, getRenderPage((domain.sitestyle == 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 1, msgid: 8, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27'), arg1: EscapeHtml(user.name), arg2: EscapeHtml(newpass) }, req, domain));
|
||||||
parent.debug('web', 'handleCheckMailRequest: send temporary password.');
|
parent.debug('web', 'handleCheckMailRequest: send temporary password.');
|
||||||
|
|
||||||
// Send to authlog
|
// Send to authlog
|
||||||
if (obj.parent.authlog) { obj.parent.authLog('https', 'Performed account reset for user ' + user.name); }
|
if (obj.parent.authlog) { obj.parent.authLog('https', 'Performed account reset for user ' + user.name); }
|
||||||
}, 0);
|
}, 0);
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
// Display a link for the user to confirm password reset
|
||||||
|
// We must do this because GMail will also load this URL a few seconds after the user does and we don't want to cause two password resets.
|
||||||
|
render(req, res, getRenderPage((domain.sitestyle == 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 1, msgid: 14, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
render(req, res, getRenderPage((domain.sitestyle == 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 1, msgid: 9, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain));
|
render(req, res, getRenderPage((domain.sitestyle == 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 1, msgid: 9, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain));
|
||||||
@ -2498,8 +2526,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
var hwstate = null;
|
var hwstate = null;
|
||||||
if (hardwareKeyChallenge) { hwstate = obj.parent.encodeCookie({ u: req.session.tokenusername, p: req.session.tokenpassword, c: req.session.u2fchallenge }, obj.parent.loginCookieEncryptionKey) }
|
if (hardwareKeyChallenge) { hwstate = obj.parent.encodeCookie({ u: req.session.tokenusername, p: req.session.tokenpassword, c: req.session.u2fchallenge }, obj.parent.loginCookieEncryptionKey) }
|
||||||
|
|
||||||
// Check if we can use OTP tokens with email
|
// Check if we can use OTP tokens with email. We can't use email for 2FA password recovery (loginmode 5).
|
||||||
var otpemail = (parent.mailserver != null) && (req.session != null) && ((req.session.tokenemail == true) || (typeof req.session.tokenemail == 'string'));
|
var otpemail = (loginmode != 5) && (parent.mailserver != null) && (req.session != null) && ((req.session.tokenemail == true) || (typeof req.session.tokenemail == 'string'));
|
||||||
if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.email2factor == false)) { otpemail = false; }
|
if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.email2factor == false)) { otpemail = false; }
|
||||||
var otpsms = (parent.smsserver != null) && (req.session != null) && (req.session.tokensms == true);
|
var otpsms = (parent.smsserver != null) && (req.session != null) && (req.session.tokensms == true);
|
||||||
if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.sms2factor == false)) { otpsms = false; }
|
if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.sms2factor == false)) { otpsms = false; }
|
||||||
|
Loading…
Reference in New Issue
Block a user