Added OTP error reporting, #3831
Ylian Saint-Hilaire committed
Apr 9, 2022 at 15:46 UTC
1947dccf9b146cda2472116fe229e34862ca1923
3 files changed
+31
-21
meshuser.js
+6
-6
@@ -3191,18 +3191,18 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
3191
case 'otpauth-request':
3192
{
3193
// Do not allow this command if 2FA's are locked
3194
- if ((domain.passwordrequirements) && (domain.passwordrequirements.lock2factor == true)) return;
3194
+ if ((domain.passwordrequirements) && (domain.passwordrequirements.lock2factor == true)) { ws.send(JSON.stringify({ action: 'otpauth-request', err: 1 })); return; }
3195
3196
// Do not allow this command if backup codes are not allowed
3197
- if ((domain.passwordrequirements) && (domain.passwordrequirements.backupcode2factor == false)) return;
3197
+ if ((domain.passwordrequirements) && (domain.passwordrequirements.backupcode2factor == false)) { ws.send(JSON.stringify({ action: 'otpauth-request', err: 2 })); return; }
3198
3199
// Do not allow this command when logged in using a login token
3200
- if (req.session.loginToken != null) break;
3200
+ if (req.session.loginToken != null) { ws.send(JSON.stringify({ action: 'otpauth-request', err: 3 })); return; }
3201
3202
// Check of OTP 2FA is allowed
3203
- if ((domain.passwordrequirements) && (domain.passwordrequirements.otp2factor == false)) break;
3203
+ if ((domain.passwordrequirements) && (domain.passwordrequirements.otp2factor == false)) { ws.send(JSON.stringify({ action: 'otpauth-request', err: 4 })); return; }
3204
3205
- if ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 1024) != 0)) return; // If this account is settings locked, return here.
3205
+ if ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 1024) != 0)) { ws.send(JSON.stringify({ action: 'otpauth-request', err: 5 })); return; } // If this account is settings locked, return here.
3206
3207
// Check if 2-step login is supported
3208
const twoStepLoginSupported = ((parent.parent.config.settings.no2factorauth !== true) && (domain.auth != 'sspi') && (parent.parent.certificates.CommonName.indexOf('.') != -1) && (args.nousers !== true));
@@ -3210,7 +3210,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
3210
// Request a one time password to be setup
3211
var otplib = null;
3212
try { otplib = require('otplib'); } catch (ex) { }
3213
- if (otplib == null) { break; }
3213
+ if (otplib == null) { ws.send(JSON.stringify({ action: 'otpauth-request', err: 6 })); return; }
3214
const secret = otplib.authenticator.generateSecret(); // TODO: Check the random source of this value.
3215
3216
var domainName = parent.certificates.CommonName;
views/default-mobile.handlebars
+12
-7
@@ -1604,13 +1604,18 @@
1604
}
1605
case 'otpauth-request': {
1606
if ((xxdialogMode == 2) && (xxdialogTag == 'otpauth-request')) {
1607
- var secret = message.secret;
1608
- if (secret.length == 52) { secret = secret.split(/(.............)/).filter(Boolean).join(' '); }
1609
- else if (secret.length == 32) { secret = secret.split(/(....)/).filter(Boolean).join(' '); secret = secret.substring(0, 20) + '<br/>' + secret.substring(20) }
1610
- QH('d2optinfo', format("Install <a href=\"https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2\" rel=\"noreferrer noopener\" target=_blank>Google Authenticator</a> or a compatible application, use <a href=\"{0}\" rel=\"noreferrer noopener\" target=_blank> this link</a> or enter the secret below. Then, enter the current 6 digit token to activate 2-Step login.", message.url) + '<br /><br /><div style=width:100%;text-align:center><tt id=d2optsecret secret="' + message.secret + '" style=font-size:15px>' + secret + '</tt><br /><br />Token: <input type=text autocomplete="one-time-code" inputmode="numeric" pattern="[0-9]*" onkeypress=\"return (event.keyCode == 8) || (event.charCode >= 48 && event.charCode <= 57)\" onkeyup=account_addOtpCheck(event) onkeydown=account_addOtpCheck() maxlength=6 id=d2otpauthinput type=text></div>');
1611
- QV('idx_dlgOkButton', true);
1612
- QE('idx_dlgOkButton', false);
1613
- Q('d2otpauthinput').focus();
1607
+ if (message.err != null) {
1608
+ var otpauthErrors = ['', "2FA is locked", "Backup codes are locked", "Login token in use", "OTP 2FA not allowed", "Account is locked", "Unable to load OTPLIB"];
1609
+ if ((message.err > 0) && (message.err < otpauthErrors.length)) { QH('d2optinfo', otpauthErrors[message.err]); } else { QH('d2optinfo', format("Error #{0}", message.err)); }
1610
+ } else {
1611
+ var secret = message.secret;
1612
+ if (secret.length == 52) { secret = secret.split(/(.............)/).filter(Boolean).join(' '); }
1613
+ else if (secret.length == 32) { secret = secret.split(/(....)/).filter(Boolean).join(' '); secret = secret.substring(0, 20) + '<br/>' + secret.substring(20) }
1614
+ QH('d2optinfo', format("Install <a href=\"https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2\" rel=\"noreferrer noopener\" target=_blank>Google Authenticator</a> or a compatible application, use <a href=\"{0}\" rel=\"noreferrer noopener\" target=_blank> this link</a> or enter the secret below. Then, enter the current 6 digit token to activate 2-Step login.", message.url) + '<br /><br /><div style=width:100%;text-align:center><tt id=d2optsecret secret="' + message.secret + '" style=font-size:15px>' + secret + '</tt><br /><br />Token: <input type=text autocomplete="one-time-code" inputmode="numeric" pattern="[0-9]*" onkeypress=\"return (event.keyCode == 8) || (event.charCode >= 48 && event.charCode <= 57)\" onkeyup=account_addOtpCheck(event) onkeydown=account_addOtpCheck() maxlength=6 id=d2otpauthinput type=text></div>');
1615
+ QV('idx_dlgOkButton', true);
1616
+ QE('idx_dlgOkButton', false);
1617
+ Q('d2otpauthinput').focus();
1618
+ }
1619
}
1620
break;
1621
}
views/default.handlebars
+13
-8
@@ -2704,14 +2704,19 @@
2704
}
2705
case 'otpauth-request': {
2706
if ((xxdialogMode == 2) && (xxdialogTag == 'otpauth-request')) {
2707
- var secret = message.secret;
2708
- if (secret.length == 52) { secret = secret.split(/(.............)/).filter(Boolean).join(' '); }
2709
- else if (secret.length == 32) { secret = secret.split(/(....)/).filter(Boolean).join(' '); secret = secret.substring(0, 20) + '<br/>' + secret.substring(20) }
2710
- QH('d2optinfo', '<table style=width:380px><tr><td style=vertical-align:top>' + format("Install <a href=\"https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2\" rel=\"noreferrer noopener\" target=_blank>Google Authenticator</a> or a compatible application and scan the barcode, use <a href=\"{0}\" rel=\"noreferrer noopener\" target=_blank>this link</a> or enter the secret. Then, enter the current 6 digit token below to activate 2-Step login.", message.url) + '<br /><br />' + "Secret" + '<br /><tt id=d2optsecret secret="' + message.secret + '" style=font-size:12px>' + secret + '</tt><br /><br /></td><td style=width:1px;vertical-align:top><a href="' + message.url + '" rel="noreferrer noopener" target=_blank><div id="qrcode"></div></a></td><tr><td colspan=2 style="text-align:center;border-top:1px solid black"><br />' + "Enter the token here for 2-step login:" + ' <input type=text autocomplete="one-time-code" inputmode="numeric" pattern="[0-9]*" onkeypress="return (event.keyCode == 8) || (event.charCode >= 48 && event.charCode <= 57)" onkeyup=account_addOtpCheck(event) onkeydown=account_addOtpCheck() maxlength=6 id=d2otpauthinput type=text></td></table>');
2711
- new QRCode(Q('qrcode'), { text: message.url, width: 128, height: 128, colorDark: '#000000', colorLight: '#EEE', correctLevel: QRCode.CorrectLevel.H });
2712
- QV('idx_dlgOkButton', true);
2713
- QE('idx_dlgOkButton', false);
2714
- Q('d2otpauthinput').focus();
2707
+ if (message.err != null) {
2708
+ var otpauthErrors = [ '', "2FA is locked", "Backup codes are locked", "Login token in use", "OTP 2FA not allowed", "Account is locked", "Unable to load OTPLIB" ];
2709
+ if ((message.err > 0) && (message.err < otpauthErrors.length)) { QH('d2optinfo', otpauthErrors[message.err]); } else { QH('d2optinfo', format("Error #{0}", message.err)); }
2710
+ } else {
2711
+ var secret = message.secret;
2712
+ if (secret.length == 52) { secret = secret.split(/(.............)/).filter(Boolean).join(' '); }
2713
+ else if (secret.length == 32) { secret = secret.split(/(....)/).filter(Boolean).join(' '); secret = secret.substring(0, 20) + '<br/>' + secret.substring(20) }
2714
+ QH('d2optinfo', '<table style=width:380px><tr><td style=vertical-align:top>' + format("Install <a href=\"https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2\" rel=\"noreferrer noopener\" target=_blank>Google Authenticator</a> or a compatible application and scan the barcode, use <a href=\"{0}\" rel=\"noreferrer noopener\" target=_blank>this link</a> or enter the secret. Then, enter the current 6 digit token below to activate 2-Step login.", message.url) + '<br /><br />' + "Secret" + '<br /><tt id=d2optsecret secret="' + message.secret + '" style=font-size:12px>' + secret + '</tt><br /><br /></td><td style=width:1px;vertical-align:top><a href="' + message.url + '" rel="noreferrer noopener" target=_blank><div id="qrcode"></div></a></td><tr><td colspan=2 style="text-align:center;border-top:1px solid black"><br />' + "Enter the token here for 2-step login:" + ' <input type=text autocomplete="one-time-code" inputmode="numeric" pattern="[0-9]*" onkeypress="return (event.keyCode == 8) || (event.charCode >= 48 && event.charCode <= 57)" onkeyup=account_addOtpCheck(event) onkeydown=account_addOtpCheck() maxlength=6 id=d2otpauthinput type=text></td></table>');
2715
+ new QRCode(Q('qrcode'), { text: message.url, width: 128, height: 128, colorDark: '#000000', colorLight: '#EEE', correctLevel: QRCode.CorrectLevel.H });
2716
+ QV('idx_dlgOkButton', true);
2717
+ QE('idx_dlgOkButton', false);
2718
+ Q('d2otpauthinput').focus();
2719
+ }
2720
}
2721
break;
2722
}