Completed email 2FA.
This commit is contained in:
parent
70e93f0c0f
commit
8a47379599
31
meshuser.js
31
meshuser.js
|
@ -1999,6 +1999,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
|||
if (command.resetNextLogin === true) { chguser.passchange = -1; } else { chguser.passchange = Math.floor(Date.now() / 1000); }
|
||||
delete chguser.passtype; // Remove the password type if one was present.
|
||||
if (command.removeMultiFactor == true) {
|
||||
if (chguser.otpekey) { delete chguser.otpekey; }
|
||||
if (chguser.otpsecret) { delete chguser.otpsecret; }
|
||||
if (chguser.otphkeys) { delete chguser.otphkeys; }
|
||||
if (chguser.otpkeys) { delete chguser.otpkeys; }
|
||||
|
@ -2984,11 +2985,33 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
|||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 'otpemail':
|
||||
{
|
||||
// Check input
|
||||
if (typeof command.enabled != 'boolean') return;
|
||||
|
||||
// See if we really need to change the state
|
||||
if ((command.enabled === true) && (user.otpekey != null)) return;
|
||||
if ((command.enabled === false) && (user.otpekey == null)) return;
|
||||
|
||||
// Change the email 2FA of this user
|
||||
if (command.enabled === true) { user.otpekey = {}; } else { delete user.otpekey; }
|
||||
parent.db.SetUser(user);
|
||||
ws.send(JSON.stringify({ action: 'otpemail', success: true, enabled: command.enabled })); // Report success
|
||||
|
||||
// Notify change
|
||||
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, account: parent.CloneSafeUser(user), action: 'accountchange', msg: command.enabled ? "Enabled email two-factor authentication." :"Disabled email two-factor authentication.", domain: domain.id };
|
||||
if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the user. Another event will come.
|
||||
parent.parent.DispatchEvent(targets, obj, event);
|
||||
break;
|
||||
}
|
||||
case 'otpauth-request':
|
||||
{
|
||||
// Check is 2-step login is supported
|
||||
// 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) {
|
||||
// Request a one time password to be setup
|
||||
|
@ -3002,7 +3025,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
|||
}
|
||||
case 'otpauth-setup':
|
||||
{
|
||||
// Check is 2-step login is supported
|
||||
// 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) {
|
||||
// Perform the one time password setup
|
||||
|
@ -3030,7 +3053,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
|||
}
|
||||
case 'otpauth-clear':
|
||||
{
|
||||
// Check is 2-step login is supported
|
||||
// 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) {
|
||||
// Clear the one time password secret
|
||||
|
@ -3053,7 +3076,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
|||
}
|
||||
case 'otpauth-getpasswords':
|
||||
{
|
||||
// Check is 2-step login is supported
|
||||
// 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;
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -252,6 +252,7 @@
|
|||
<div id="p3AccountActions">
|
||||
<p><strong>Account Security</strong></p>
|
||||
<div style="margin-left:9px;margin-bottom:8px">
|
||||
<div id="manageEmail2FA" style="margin-top:5px;display:none"><a onclick="account_manageAuthEmail()" style="cursor:pointer">Manage email authentication</a></div>
|
||||
<div id="manageAuthApp" style="margin-top:5px;display:none"><a onclick="account_manageAuthApp()" style="cursor:pointer">Manage authenticator app</a></div>
|
||||
<div id="manageOtp" style="margin-top:5px;display:none"><a onclick="account_manageOtp(0)" style="cursor:pointer">Manage backup codes</a></div>
|
||||
</div>
|
||||
|
@ -666,6 +667,9 @@
|
|||
var t = localStorage.getItem('desktopsettings');
|
||||
if (t != null) { desktopsettings = JSON.parse(t); }
|
||||
applyDesktopSettings();
|
||||
|
||||
// Arrange the user interface
|
||||
QV('manageEmail2FA', features & 0x00800000);
|
||||
}
|
||||
|
||||
function onStateChanged(server, state, prevState, errorCode) {
|
||||
|
@ -1215,6 +1219,14 @@
|
|||
// MY ACCOUNT
|
||||
//
|
||||
|
||||
function account_manageAuthEmail() {
|
||||
if (xxdialogMode || ((features & 0x00800000) == 0)) return;
|
||||
var emailU2Fenabled = ((userinfo.otpekey == 1) && (userinfo.email != null) && (userinfo.emailVerified == true));
|
||||
setDialogMode(2, "Email Authentication", 1, function () {
|
||||
if (emailU2Fenabled != Q('email2facheck').checked) { meshserver.send({ action: 'otpemail', enabled: Q('email2facheck').checked }); }
|
||||
}, "When enabled, on each login, you will be given the option to receive a login token to you email account for added security." + '<br /><br /><label><input id=email2facheck type=checkbox ' + (emailU2Fenabled ? 'checked' : '') + '/>' + "Enable email two-factor authenticaiton." + '</label>');
|
||||
}
|
||||
|
||||
function account_manageAuthApp() {
|
||||
if (xxdialogMode || ((features & 4096) == 0)) return;
|
||||
if (userinfo.otpsecret == 1) { account_removeOtp(); } else { account_addOtp(); }
|
||||
|
@ -1324,7 +1336,7 @@
|
|||
if ((userinfo.emailVerified !== true) && (serverinfo.emailcheck == true) && (userinfo.siteadmin != 0xFFFFFFFF)) { setDialogMode(2, "Account Security", 1, null, "Unable to access a device until a email address is verified. This is required for password recovery. Go to the \"My Account\" to change and verify an email address."); return; }
|
||||
|
||||
// Remind the user to add two factor authentication
|
||||
if ((features & 0x00040000) && !((userinfo.otpsecret == 1) || (userinfo.otphkeys > 0) || (userinfo.otpkeys > 0))) { setDialogMode(2, "Account Security", 1, null, "Unable to access a device until two-factor authentication is enabled. This is required for extra security. Go to the \"My Account\" and look at the \"Account Security\" section."); return; }
|
||||
if ((features & 0x00040000) && !((userinfo.otpsecret == 1) || (userinfo.otphkeys > 0) || (userinfo.otpkeys > 0) || ((features & 0x00800000) && (userinfo.otpekey == 1)))) { setDialogMode(2, "Account Security", 1, null, "Unable to access a device until two-factor authentication is enabled. This is required for extra security. Go to the \"My Account\" and look at the \"Account Security\" section."); return; }
|
||||
|
||||
// We are allowed, let's prompt to information
|
||||
var x = addHtmlValue("Name", '<input id=dp3meshname style=width:170px maxlength=64 onchange=account_validateMeshCreate() onkeyup=account_validateMeshCreate() />');
|
||||
|
@ -1891,7 +1903,7 @@
|
|||
if ((userinfo.emailVerified !== true) && (serverinfo.emailcheck == true) && (userinfo.siteadmin != 0xFFFFFFFF)) { setDialogMode(2, "Account Security", 1, null, "Unable to access a device until a email address is verified. This is required for password recovery. Go to the \"My Account\" to change and verify an email address."); return; }
|
||||
|
||||
// Remind the user to add two factor authentication
|
||||
if ((features & 0x00040000) && !((userinfo.otpsecret == 1) || (userinfo.otphkeys > 0) || (userinfo.otpkeys > 0))) { setDialogMode(2, "Account Security", 1, null, "Unable to access a device until two-factor authentication is enabled. This is required for extra security. Go to the \"My Account\" and look at the \"Account Security\" section."); return; }
|
||||
if ((features & 0x00040000) && !((userinfo.otpsecret == 1) || (userinfo.otphkeys > 0) || (userinfo.otpkeys > 0) || ((features & 0x00800000) && (userinfo.otpekey == 1)))) { setDialogMode(2, "Account Security", 1, null, "Unable to access a device until two-factor authentication is enabled. This is required for extra security. Go to the \"My Account\" and look at the \"Account Security\" section."); return; }
|
||||
|
||||
var node = getNodeFromId(nodeid);
|
||||
if (node == null) { goBack(); return; }
|
||||
|
|
|
@ -301,6 +301,7 @@
|
|||
<div id="p2AccountSecurity" style="display:none">
|
||||
<p><strong>Account security</strong></p>
|
||||
<div style="margin-left:25px">
|
||||
<div id="manageEmail2FA"><div class="p2AccountActions"><span id="authEmailSetupCheck"><strong>✓</strong></span></div><span><a href=# onclick="return account_manageAuthEmail()">Manage email authentication</a><br /></span></div>
|
||||
<div id="manageAuthApp"><div class="p2AccountActions"><span id="authAppSetupCheck"><strong>✓</strong></span></div><span><a href=# onclick="return account_manageAuthApp()">Manage authenticator app</a><br /></span></div>
|
||||
<div id="manageHardwareOtp"><div class="p2AccountActions"><span id="authKeySetupCheck"><strong>✓</strong></span></div><span><a href=# onclick="return account_manageHardwareOtp(0)">Manage security keys</a><br /></span></div>
|
||||
<div id="manageOtp"><div class="p2AccountActions"><span id="authCodesSetupCheck"><strong>✓</strong></span></div><span><a href=# onclick="return account_manageOtp(0)">Manage backup codes</a><br /></span></div>
|
||||
|
@ -1590,6 +1591,7 @@
|
|||
|
||||
// Update account actions
|
||||
QV('p2AccountSecurity', ((features & 4) == 0) && (serverinfo.domainauth == false) && ((features & 4096) != 0)); // Hide Account Security if in single user mode, domain authentication to 2 factor auth not supported.
|
||||
QV('manageEmail2FA', features & 0x00800000);
|
||||
QV('p2AccountPassActions', ((features & 4) == 0) && (serverinfo.domainauth == 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('p2ServerActions', siteRights & 21);
|
||||
|
@ -1660,13 +1662,19 @@
|
|||
QV('verifyEmailId', (userinfo.emailVerified !== true) && (userinfo.email != null) && (serverinfo.emailcheck == true));
|
||||
QV('verifyEmailId2', (userinfo.emailVerified !== true) && (userinfo.email != null) && (serverinfo.emailcheck == true));
|
||||
QV('manageOtp', (userinfo.otpsecret == 1) || (userinfo.otphkeys > 0));
|
||||
QV('authEmailSetupCheck', (userinfo.otpekey == 1) && (userinfo.email != null) && (userinfo.emailVerified == true));
|
||||
QV('authAppSetupCheck', userinfo.otpsecret == 1);
|
||||
QV('authKeySetupCheck', userinfo.otphkeys > 0);
|
||||
QV('authCodesSetupCheck', userinfo.otpkeys > 0);
|
||||
masterUpdate(4 + 128 + 4096);
|
||||
|
||||
// Check if backup codes should really be enabled
|
||||
if ((backupCodesWarningDone == false) && !(userinfo.otpkeys > 0) && (((userinfo.otpsecret == 1) && !(userinfo.otphkeys > 0)) || ((userinfo.otpsecret != 1) && (userinfo.otphkeys == 1)))) {
|
||||
// Check if none or at least 2 factors are enabled.
|
||||
var authFactorCount = 0;
|
||||
if ((features & 0x00800000) && (userinfo.otpekey == 1)) { authFactorCount += 1; }
|
||||
if (userinfo.otpkeys == 1) { authFactorCount += 1; }
|
||||
if (userinfo.otpsecret == 1) { authFactorCount += 1; }
|
||||
if (userinfo.otphkeys != null) { authFactorCount += userinfo.otphkeys; }
|
||||
if ((backupCodesWarningDone == false) && (authFactorCount == 1)) {
|
||||
var n = { text: "Please add two-factor backup codes. If the current factor is lost, there is not way to recover this account.", title: "Two factor authentication" };
|
||||
addNotification(n);
|
||||
backupCodesWarningDone = true;
|
||||
|
@ -4743,7 +4751,7 @@
|
|||
if ((userinfo.emailVerified !== true) && (serverinfo.emailcheck == true) && (userinfo.siteadmin != 0xFFFFFFFF)) { setDialogMode(2, "Account Security", 1, null, "Unable to access a device until a email address is verified. This is required for password recovery. Go to the \"My Account\" tab to change and verify an email address."); return; }
|
||||
|
||||
// Remind the user to add two factor authentication
|
||||
if ((features & 0x00040000) && !((userinfo.otpsecret == 1) || (userinfo.otphkeys > 0) || (userinfo.otpkeys > 0))) { setDialogMode(2, "Account Security", 1, null, "Unable to access a device until two-factor authentication is enabled. This is required for extra security. Go to the \"My Account\" tab and look at the \"Account Security\" section."); return; }
|
||||
if ((features & 0x00040000) && !((userinfo.otpsecret == 1) || (userinfo.otphkeys > 0) || (userinfo.otpkeys > 0) || ((features & 0x00800000) && (userinfo.otpekey == 1)))) { setDialogMode(2, "Account Security", 1, null, "Unable to access a device until two-factor authentication is enabled. This is required for extra security. Go to the \"My Account\" tab and look at the \"Account Security\" section."); return; }
|
||||
|
||||
if (event && (event.shiftKey == true)) {
|
||||
// Open the device in a different tab
|
||||
|
@ -7689,6 +7697,14 @@
|
|||
// MY ACCOUNT
|
||||
//
|
||||
|
||||
function account_manageAuthEmail() {
|
||||
if (xxdialogMode || ((features & 0x00800000) == 0)) return;
|
||||
var emailU2Fenabled = ((userinfo.otpekey == 1) && (userinfo.email != null) && (userinfo.emailVerified == true));
|
||||
setDialogMode(2, "Email Authentication", 1, function () {
|
||||
if (emailU2Fenabled != Q('email2facheck').checked) { meshserver.send({ action: 'otpemail', enabled: Q('email2facheck').checked }); }
|
||||
}, "When enabled, on each login, you will be given the option to receive a login token to you email account for added security." + '<br /><br /><label><input id=email2facheck type=checkbox ' + (emailU2Fenabled?'checked':'') + '/>' + "Enable email two-factor authenticaiton." + '</label>');
|
||||
}
|
||||
|
||||
function account_manageAuthApp() {
|
||||
if (xxdialogMode || ((features & 4096) == 0)) return;
|
||||
if (userinfo.otpsecret == 1) { account_removeOtp(); } else { account_addOtp(); }
|
||||
|
@ -7928,7 +7944,7 @@
|
|||
if ((userinfo.emailVerified !== true) && (serverinfo.emailcheck == true) && (userinfo.siteadmin != 0xFFFFFFFF)) { setDialogMode(2, "Account Security", 1, null, "Unable to access a device until a email address is verified. This is required for password recovery. Go to the \"My Account\" tab to change and verify an email address."); return false; }
|
||||
|
||||
// Remind the user to add two factor authentication
|
||||
if ((features & 0x00040000) && !((userinfo.otpsecret == 1) || (userinfo.otphkeys > 0) || (userinfo.otpkeys > 0))) { setDialogMode(2, "Account Security", 1, null, "Unable to access a device until two-factor authentication is enabled. This is required for extra security. Go to the \"My Account\" tab and look at the \"Account Security\" section."); return false; }
|
||||
if ((features & 0x00040000) && !((userinfo.otpsecret == 1) || (userinfo.otphkeys > 0) || (userinfo.otpkeys > 0) || ((features & 0x00800000) && (userinfo.otpekey == 1)))) { setDialogMode(2, "Account Security", 1, null, "Unable to access a device until two-factor authentication is enabled. This is required for extra security. Go to the \"My Account\" tab and look at the \"Account Security\" section."); return false; }
|
||||
|
||||
// We are allowed, let's prompt to information
|
||||
var x = "Create a new device group using the options below." + '<br /><br />';
|
||||
|
|
|
@ -552,7 +552,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||
|
||||
// Check if we can use OTP tokens with email
|
||||
var otpemail = (parent.mailserver != null);
|
||||
if ((typeof domain.passwordrequirements == 'object') && (typeof domain.passwordrequirements.email2factor == false)) { otpemail = false; }
|
||||
if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.email2factor == false)) { otpemail = false; }
|
||||
|
||||
// Check email key
|
||||
if ((otpemail) && (user.otpekey != null) && (user.otpekey.d != null) && (user.otpekey.k === token)) {
|
||||
|
@ -1625,6 +1625,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||
if (domain.amtacmactivation) { features += 0x00100000; } // Intel AMT ACM activation/upgrade is possible
|
||||
if (domain.usernameisemail) { features += 0x00200000; } // Username is email address
|
||||
if (parent.mqttbroker != null) { features += 0x00400000; } // This server supports MQTT channels
|
||||
if (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (parent.mailserver != null)) { features += 0x00800000; } // using email for 2FA is allowed
|
||||
|
||||
// Create a authentication cookie
|
||||
const authCookie = obj.parent.encodeCookie({ userid: user._id, domainid: domain.id, ip: cleanRemoteAddr(req.ip) }, obj.parent.loginCookieEncryptionKey);
|
||||
|
@ -1721,7 +1722,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||
|
||||
// Check if we can use OTP tokens with email
|
||||
var otpemail = (parent.mailserver != null) && (req.session.tokenemail);
|
||||
if ((typeof domain.passwordrequirements == 'object') && (typeof domain.passwordrequirements.email2factor == false)) { otpemail = false; }
|
||||
if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.email2factor == false)) { otpemail = false; }
|
||||
|
||||
// Render the login page
|
||||
render(req, res, getRenderPage('login', req), getRenderArgs({ loginmode: loginmode, rootCertLink: getRootCertLink(), newAccount: newAccountsAllowed, newAccountPass: (((domain.newaccountspass == null) || (domain.newaccountspass == '')) ? 0 : 1), serverDnsName: obj.getWebServerName(domain), serverPublicPort: httpsPort, emailcheck: emailcheck, features: features, sessiontime: args.sessiontime, passRequirements: passRequirements, footer: (domain.footer == null) ? '' : domain.footer, hkey: encodeURIComponent(hardwareKeyChallenge), messageid: msgid, passhint: passhint, welcometext: domain.welcometext ? encodeURIComponent(domain.welcometext).split('\'').join('\\\'') : null, hwstate: hwstate, otpemail: otpemail }, domain));
|
||||
|
@ -4274,7 +4275,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||
delete user2.domain;
|
||||
delete user2.subscriptions;
|
||||
delete user2.passtype;
|
||||
if ((typeof user2.otpkeys == 'object') && (user2.otpkeys != null)) { user2.otpekey = 1; } // Indicates that email 2FA is enabled.
|
||||
if ((typeof user2.otpekey == 'object') && (user2.otpekey != null)) { user2.otpekey = 1; } // Indicates that email 2FA is enabled.
|
||||
if ((typeof user2.otpsecret == 'string') && (user2.otpsecret != null)) { user2.otpsecret = 1; } // Indicates a time secret is present.
|
||||
if ((typeof user2.otpkeys == 'object') && (user2.otpkeys != null)) { user2.otpkeys = 0; if (user.otpkeys != null) { for (var i = 0; i < user.otpkeys.keys.length; i++) { if (user.otpkeys.keys[i].u == true) { user2.otpkeys = 1; } } } } // Indicates the number of one time backup codes that are active.
|
||||
if ((typeof user2.otphkeys == 'object') && (user2.otphkeys != null)) { user2.otphkeys = user2.otphkeys.length; } // Indicates the number of hardware keys setup
|
||||
|
|
Loading…
Reference in New Issue