diff --git a/meshuser.js b/meshuser.js index de2246bb..812b0550 100644 --- a/meshuser.js +++ b/meshuser.js @@ -1342,58 +1342,72 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use } case 'otpauth-request': { - // Request a one time password to be setup - const otplib = require('otplib'); - const secret = otplib.authenticator.generateSecret(); - ws.send(JSON.stringify({ action: 'otpauth-request', secret: secret, url: otplib.authenticator.keyuri(user.name, 'MeshCentral', secret) })); + // Check is 2-step login is supported + const twoStepLoginSupported = ((domain.auth != 'sspi') && (obj.parent.parent.certificates.CommonName != 'un-configured') && (obj.args.lanonly !== true) && (obj.args.nousers !== true)); + if (twoStepLoginSupported) { + // Request a one time password to be setup + const otplib = require('otplib'); + const secret = otplib.authenticator.generateSecret(); // TODO: Check the random source of this value. + ws.send(JSON.stringify({ action: 'otpauth-request', secret: secret, url: otplib.authenticator.keyuri(user.name, obj.parent.certificates.CommonName, secret) })); + } break; } case 'otpauth-setup': { - // Perform the one time password setup - if (require('otplib').authenticator.check(command.token, command.secret) === true) { - // Token is valid, activate 2-step login on this account. - user.otpsecret = command.secret; - obj.parent.db.SetUser(user); - ws.send(JSON.stringify({ action: 'otpauth-setup', success: true })); // Report success + // Check is 2-step login is supported + const twoStepLoginSupported = ((domain.auth != 'sspi') && (obj.parent.parent.certificates.CommonName != 'un-configured') && (obj.args.lanonly !== true) && (obj.args.nousers !== true)); + if (twoStepLoginSupported) { + // Perform the one time password setup + const otplib = require('otplib'); + otplib.authenticator.options = { window: 6 }; // Set +/- 3 minute window + if (otplib.authenticator.check(command.token, command.secret) === true) { + // Token is valid, activate 2-step login on this account. + user.otpsecret = command.secret; + obj.parent.db.SetUser(user); + ws.send(JSON.stringify({ action: 'otpauth-setup', success: true })); // Report success - // Notify change - var userinfo = obj.common.Clone(user); - delete userinfo.hash; - delete userinfo.passhint; - delete userinfo.salt; - delete userinfo.type; - delete userinfo.domain; - delete userinfo.subscriptions; - delete userinfo.passtype; - if (userinfo.otpsecret) { userinfo.otpsecret = 1; } - try { ws.send(JSON.stringify({ action: 'userinfo', userinfo: userinfo })); } catch (ex) { } - } else { - ws.send(JSON.stringify({ action: 'otpauth-setup', success: false })); // Report fail + // Notify change + var userinfo = obj.common.Clone(user); + delete userinfo.hash; + delete userinfo.passhint; + delete userinfo.salt; + delete userinfo.type; + delete userinfo.domain; + delete userinfo.subscriptions; + delete userinfo.passtype; + if (userinfo.otpsecret) { userinfo.otpsecret = 1; } + try { ws.send(JSON.stringify({ action: 'userinfo', userinfo: userinfo })); } catch (ex) { } + } else { + ws.send(JSON.stringify({ action: 'otpauth-setup', success: false })); // Report fail + } } break; } case 'otpauth-clear': { - // Clear the one time password secret - if (user.otpsecret) { - delete user.otpsecret; - obj.parent.db.SetUser(user); + // Check is 2-step login is supported + const twoStepLoginSupported = ((domain.auth != 'sspi') && (obj.parent.parent.certificates.CommonName != 'un-configured') && (obj.args.lanonly !== true) && (obj.args.nousers !== true)); + if (twoStepLoginSupported) { + // Clear the one time password secret + if (user.otpsecret) { + delete user.otpsecret; + obj.parent.db.SetUser(user); - // Notify change - var userinfo = obj.common.Clone(user); - delete userinfo.hash; - delete userinfo.passhint; - delete userinfo.salt; - delete userinfo.type; - delete userinfo.domain; - delete userinfo.subscriptions; - delete userinfo.passtype; - if (userinfo.otpsecret) { userinfo.otpsecret = 1; } - try { ws.send(JSON.stringify({ action: 'userinfo', userinfo: userinfo })); } catch (ex) { } - ws.send(JSON.stringify({ action: 'otpauth-clear', success: true })); // Report success - } else { - ws.send(JSON.stringify({ action: 'otpauth-clear', success: false })); // Report fail + // Notify change + var userinfo = obj.common.Clone(user); + delete userinfo.hash; + delete userinfo.passhint; + delete userinfo.salt; + delete userinfo.type; + delete userinfo.domain; + delete userinfo.subscriptions; + delete userinfo.passtype; + if (userinfo.otpsecret) { userinfo.otpsecret = 1; } + try { ws.send(JSON.stringify({ action: 'userinfo', userinfo: userinfo })); } catch (ex) { } + ws.send(JSON.stringify({ action: 'otpauth-clear', success: true })); // Report success + } else { + ws.send(JSON.stringify({ action: 'otpauth-clear', success: false })); // Report fail + } } break; } diff --git a/views/default.handlebars b/views/default.handlebars index 6e46b67d..b119c1c0 100644 --- a/views/default.handlebars +++ b/views/default.handlebars @@ -1121,10 +1121,8 @@ updateSiteAdmin(); QV('verifyEmailId', (userinfo.emailVerified !== true) && (userinfo.email != null) && (serverinfo.emailcheck == true)); QV('verifyEmailId2', (userinfo.emailVerified !== true) && (userinfo.email != null) && (serverinfo.emailcheck == true)); - if ((features & 4096) != 0) { - QV('otpAuth', (userinfo.otpsecret != 1)); - QV('otpAuthRemove', (userinfo.otpsecret == 1)); - } + QV('otpAuth', ((features & 4096) != 0) && (userinfo.otpsecret != 1)); + QV('otpAuthRemove', ((features & 4096) != 0) && (userinfo.otpsecret == 1)); break; } case 'users': { @@ -1315,7 +1313,10 @@ } case 'otpauth-request': { if ((xxdialogMode == 2) && (xxdialogTag == 'otpauth-request')) { - QH('d2optinfo', '
Install Google Authenticator or a compatible application and scan the barcode, use this link or enter the secret. Then, enter the current 6 digit token below to activate 2-Step login.

Secret
' + message.secret + '


Enter the token here for 2-step login: = 48 && event.charCode <= 57)\" onkeyup=account_addOtpCheck() onkeydown=account_addOtpCheck() maxlength=6 id=d2otpauthinput type="text">
'); + var secret = message.secret; + if (secret.length == 52) { secret = secret.split(/(.............)/).filter(Boolean).join(' '); } + else if (secret.length == 32) { secret = secret.split(/(....)/).filter(Boolean).join(' '); secret = secret.substring(0, 20) + '
' + secret.substring(20) } + QH('d2optinfo', '
Install Google Authenticator or a compatible application and scan the barcode, use this link or enter the secret. Then, enter the current 6 digit token below to activate 2-Step login.

Secret
' + secret + '


Enter the token here for 2-step login: = 48 && event.charCode <= 57)\" onkeyup=account_addOtpCheck(event) onkeydown=account_addOtpCheck() maxlength=6 id=d2otpauthinput type=text>
'); new QRCode(Q("qrcode"), { text: message.url, width: 128, height: 128, colorDark: "#000000", colorLight: "#EEE", correctLevel: QRCode.CorrectLevel.H }); QV('idx_dlgOkButton', true); QE('idx_dlgOkButton', false); @@ -5056,12 +5057,14 @@ function account_addOtp() { if (xxdialogMode || (userinfo.otpsecret == 1) || ((features & 4096) == 0)) return; - setDialogMode(2, "Add 2-Step Login", 2, function () { meshserver.send({ action: 'otpauth-setup', secret: Q('d2optsecret').innerHTML, token: Q('d2otpauthinput').value }); }, "
Loading...
", 'otpauth-request'); + setDialogMode(2, "Add 2-Step Login", 2, function () { meshserver.send({ action: 'otpauth-setup', secret: Q('d2optsecret').attributes.secret.value, token: Q('d2otpauthinput').value }); }, "
Loading...
", 'otpauth-request'); meshserver.send({ action: 'otpauth-request' }); } - function account_addOtpCheck() { - QE('idx_dlgOkButton', Q('d2otpauthinput').value.length == 6); + function account_addOtpCheck(e) { + const v = (Q('d2otpauthinput').value.length == 6); + QE('idx_dlgOkButton', v); + if (e && (e.keyCode == 13) && v) { dialogclose(1); } } function account_removeOtp() { diff --git a/views/login-mobile.handlebars b/views/login-mobile.handlebars index 63c82b29..5b1f8c04 100644 --- a/views/login-mobile.handlebars +++ b/views/login-mobile.handlebars @@ -117,7 +117,7 @@ -