Added support for 2FA messaging (#4650)
Ylian Saint-Hilaire committed
Oct 22, 2022 at 12:59 UTC
e2cf723c6a95f6c472d7eb38a50e19c677e5b643
8 files changed
+139
-13
meshmessaging.js
+1
-1
@@ -69,7 +69,7 @@ module.exports.CreateServer = function (parent) {
69
async function sendTelegramMessage(to, msg, func) {
70
if (obj.telegramClient == null) return;
71
parent.debug('email', 'Sending Telegram message to: ' + to.substring(9) + ': ' + msg);
72
- try { await obj.telegramClient.sendMessage(to.substring(9), { message: msg }); func(true); } catch (ex) { func(false, ex); }
72
+ try { await obj.telegramClient.sendMessage(to.substring(9), { message: msg }); if (func != null) { func(true); } } catch (ex) { if (func != null) { func(false, ex); } }
73
}
74
sendTelegramMessage(to, msg, func);
75
} else {
meshuser.js
+2
@@ -7941,10 +7941,12 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
7941
function count2factoraAuths() {
7942
var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (domain.mailserver != null));
7943
var sms2fa = ((parent.parent.smsserver != null) && ((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)));
7944
+ var msg2fa = ((parent.parent.msgserver != null) && (parent.parent.msgserver.providers != 0) && ((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.msg2factor != false)));
7945
var authFactorCount = 0;
7946
if (typeof user.otpsecret == 'string') { authFactorCount++; } // Authenticator time factor
7947
if (email2fa && (user.otpekey != null)) { authFactorCount++; } // EMail factor
7948
if (sms2fa && (user.phone != null)) { authFactorCount++; } // SMS factor
7949
+ if (msg2fa && (user.msghandle != null)) { authFactorCount++; } // Messaging factor
7950
if (user.otphkeys != null) { authFactorCount += user.otphkeys.length; } // FIDO hardware factor
7951
if ((authFactorCount > 0) && (user.otpkeys != null)) { authFactorCount++; } // Backup keys
7952
return authFactorCount;
public/images/login/2fa-messaging-48.png
Binary files /dev/null and b/public/images/login/2fa-messaging-48.png differ
public/images/login/2fa-messaging-96.png
Binary files /dev/null and b/public/images/login/2fa-messaging-96.png differ
views/default.handlebars
+2
@@ -2230,6 +2230,7 @@
2230
if (userinfo.otphkeys > 0) { authFactorCount += userinfo.otphkeys; } // FIDO hardware factor
2231
if ((features & 0x00800000) && (userinfo.otpekey == 1)) { authFactorCount++; } // EMail factor
2232
if ((features & 0x02000000) && (features & 0x04000000) && (userinfo.phone != null)) { authFactorCount++; } // SMS factor
2233
+ if ((features2 & 0x02000000) && (features2 & 0x04000000) && (userinfo.msghandle != null)) { authFactorCount++; } // Messaging factor
2234
if ((authFactorCount > 0) && (userinfo.otpkeys > 0) && ((features2 & 0x40000) == 0)) { authFactorCount++; } // Backup keys
2235
return authFactorCount;
2236
}
@@ -16738,6 +16739,7 @@
16739
if (v == 'fido') { return "FIDO key"; }
16740
if (v == 'sms') { return "SMS message"; }
16741
if (v == 'hwotp') { return "Hardware OTP"; }
16742
+ if (v == 'messenger') { return "Messenging"; }
16743
if (v == 'push') { return "Push Notification"; }
16744
if (v == 'otp') { return "One-Time Password"; }
16745
if (v == 'cookie') { return "Remember Device"; }
views/login.handlebars
+23
-1
@@ -190,6 +190,7 @@
190
<input style="display:none;float:right" id=securityKeyButton type=button value="Use Security Key" onclick="useSecurityKey(1)" />
191
<input style="display:none;float:right" id=emailKeyButton type=button value="Email" onclick="useEmailToken(1)" />
192
<input style="display:none;float:right" id=smsKeyButton type=button value="SMS" onclick="useSMSToken(1)" />
193
+ <input style="display:none;float:right" id=msgKeyButton type=button value="Messaging" onclick="useMsgToken(1)" />
194
</div>
195
</td>
196
</tr>
@@ -217,6 +218,7 @@
218
<input style="display:none;float:right" id=securityKeyButton2 type=button value="Use Security Key" onclick="useSecurityKey(2)" />
219
<input style="display:none;float:right" id=emailKeyButton2 type=button value="Email" onclick="useEmailToken(2)" />
220
<input style="display:none;float:right" id=smsKeyButton2 type=button value="SMS" onclick="useSMSToken(2)" />
221
+ <input style="display:none;float:right" id=msgKeyButton2 type=button value="Messaging" onclick="useMsgToken(2)" />
222
</div>
223
</td>
224
</tr>
@@ -335,6 +337,7 @@
337
var publicKeyCredentialRequestOptions = null;
338
var otpemail = (decodeURIComponent('{{{otpemail}}}') === 'true');
339
var otpsms = (decodeURIComponent('{{{otpsms}}}') === 'true');
340
+ var otpmsg = (decodeURIComponent('{{{otpmsg}}}') === 'true');
341
var autofido = (decodeURIComponent('{{{autofido}}}') === 'true');
342
var twoFactorCookieDays = parseInt('{{{twoFactorCookieDays}}}');
343
var authStrategies = '{{{authStrategies}}}'.split(',');
@@ -344,7 +347,7 @@
347
// Display the right server message
348
var i;
349
var messageid = parseInt('{{{messageid}}}');
347
- var okmessages = ['', "If valid, reset mail sent.", "Email sent.", "Email verification required, check your mailbox and click the confirmation link.", "SMS sent."];
350
+ var okmessages = ['', "If valid, reset mail sent.", "Email sent.", "Email verification required, check your mailbox and click the confirmation link.", "SMS sent.", "Sending notification...", "Message sent."];
351
var failmessages = ["Unable to create account.", "Account limit reached.", "Existing account with this email address.", "Invalid account creation token.", "Username already exists.", "Password rejected, use a different one.", "Invalid email.", "Account not found.", "Invalid token, try again.", "Unable to sent email.", "Account locked.", "Access denied.", "Login failed, check username and password.", "Password change requested.", "IP address blocked, try again later.", "Server under maintenance.", "Unable to send device notification.", "Invalid security check."];
352
if (messageid > 0) {
353
var msg = '';
@@ -455,6 +458,7 @@
458
QV('securityKeyButton', twofakey);
459
QV('emailKeyButton', otpemail && (messageid != 2) && (messageid != 4));
460
QV('smsKeyButton', otpsms && (messageid != 2) && (messageid != 4));
461
+ QV('msgKeyButton', otpmsg && (messageid != 2) && (messageid != 4));
462
463
// If hardware key is an option, trigger it now
464
if (autofido && twofakey) { setTimeout(function () { useSecurityKey(1); }, 300); }
@@ -467,6 +471,7 @@
471
QV('securityKeyButton2', twofakey);
472
QV('emailKeyButton2', otpemail && (messageid != 2) && (messageid != 4));
473
QV('smsKeyButton2', otpsms && (messageid != 2) && (messageid != 4));
474
+ QV('msgKeyButton2', otpmsg && (messageid != 2) && (messageid != 4));
475
476
// If hardware key is an option, trigger it now
477
if (autofido && twofakey) { setTimeout(function () { useSecurityKey(2); }, 300); }
@@ -580,6 +585,23 @@
585
}
586
}
587
588
+ function useMsgToken(panelAction) {
589
+ if (otpmsg != true) return;
590
+ setDialogMode(1, "Secure Login", 3, useMsgTokenEx, "Send token to messaging application?", panelAction);
591
+ }
592
+
593
+ function useMsgTokenEx(b, panelAction) {
594
+ if (panelAction == 1) {
595
+ Q('hwtokenInput').value = '**msg**';
596
+ QE('tokenOkButton', true);
597
+ Q('tokenOkButton').click();
598
+ } else if (panelAction == 2) {
599
+ Q('resetHwtokenInput').value = '**msg**';
600
+ QE('resetTokenOkButton', true);
601
+ Q('resetTokenOkButton').click();
602
+ }
603
+ }
604
+
605
function showPassHint(e) {
606
messagebox("Password Hint", passhint);
607
haltEvent(e);
views/login2.handlebars
+27
-3
@@ -217,6 +217,7 @@
217
<div>
218
<img id=securityKeyButton src="images/login/2fa-key-48.png" srcset="images/login/2fa-key-96.png 2x" title="Use Security Key" loading="lazy" width="48" height="48" style="display:none;margin-left:3px;margin-right:3px;border-radius:3px;box-shadow:2px 2px 5px black;cursor:pointer;background-color:#FFF" onclick="useSecurityKey(1)" />
219
<img id=smsKeyButton src="images/login/2fa-sms-48.png" srcset="images/login/2fa-sms-96.png 2x" title="SMS" loading="lazy" width="48" height="48" style="display:none;margin-left:3px;margin-right:3px;border-radius:3px;box-shadow:2px 2px 5px black;cursor:pointer;background-color:#FFF" onclick="useSMSToken(1)" />
220
+ <img id=msgKeyButton src="images/login/2fa-messaging-48.png" srcset="images/login/2fa-messaging-96.png 2x" title="Messaging" loading="lazy" width="48" height="48" style="display:none;margin-left:3px;margin-right:3px;border-radius:3px;box-shadow:2px 2px 5px black;cursor:pointer;background-color:#FFF" onclick="useMsgToken(1)" />
221
<img id=emailKeyButton src="images/login/2fa-mail-48.png" srcset="images/login/2fa-mail-96.png 2x" title="Email" loading="lazy" width="48" height="48" style="display:none;margin-left:3px;margin-right:3px;border-radius:3px;box-shadow:2px 2px 5px black;cursor:pointer;background-color:#FFF" onclick="useEmailToken(1)" />
222
<img id=pushKeyButton src="images/login/2fa-push-48.png" srcset="images/login/2fa-push-96.png 2x" title="Device Authentication" loading="lazy" width="48" height="48" style="display:none;margin-left:3px;margin-right:3px;border-radius:3px;box-shadow:2px 2px 5px black;cursor:pointer;background-color:#FFF" onclick="usePushToken(1)" />
223
</div>
@@ -251,6 +252,7 @@
252
<div>
253
<img id=securityKeyButton2 src="images/login/2fa-key-48.png" srcset="images/login/2fa-key-96.png 2x" title="Use Security Key" loading="lazy" width="48" height="48" style="display:none;margin-left:3px;margin-right:3px;border-radius:3px;box-shadow:2px 2px 5px black;cursor:pointer;background-color:#FFF" onclick="useSecurityKey(2)" />
254
<img id=smsKeyButton2 src="images/login/2fa-sms-48.png" srcset="images/login/2fa-sms-96.png 2x" title="SMS" loading="lazy" width="48" height="48" style="display:none;margin-left:3px;margin-right:3px;border-radius:3px;box-shadow:2px 2px 5px black;cursor:pointer;background-color:#FFF" onclick="useSMSToken(2)" />
255
+ <img id=msgKeyButton2 src="images/login/2fa-msg-48.png" srcset="images/login/2fa-msg-96.png 2x" title="SMS" loading="lazy" width="48" height="48" style="display:none;margin-left:3px;margin-right:3px;border-radius:3px;box-shadow:2px 2px 5px black;cursor:pointer;background-color:#FFF" onclick="useMsgToken(2)" />
256
<img id=emailKeyButton2 src="images/login/2fa-mail-48.png" srcset="images/login/2fa-mail-96.png 2x" title="Email" loading="lazy" width="48" height="48" style="display:none;margin-left:3px;margin-right:3px;border-radius:3px;box-shadow:2px 2px 5px black;cursor:pointer;background-color:#FFF" onclick="useEmailToken(2)" />
257
<img id=pushKeyButton2 src="images/login/2fa-push-48.png" srcset="images/login/2fa-push-96.png 2x" title="Device Authentication" loading="lazy" width="48" height="48" style="display:none;margin-left:3px;margin-right:3px;border-radius:3px;box-shadow:2px 2px 5px black;cursor:pointer;background-color:#FFF" onclick="usePushToken(2)" />
258
</div>
@@ -389,6 +391,7 @@
391
var publicKeyCredentialRequestOptions = null;
392
var otpemail = (decodeURIComponent('{{{otpemail}}}') === 'true');
393
var otpsms = (decodeURIComponent('{{{otpsms}}}') === 'true');
394
+ var otpmsg = (decodeURIComponent('{{{otpmsg}}}') === 'true');
395
var otppush = (decodeURIComponent('{{{otppush}}}') === 'true');
396
var autofido = (decodeURIComponent('{{{autofido}}}') === 'true');
397
var twoFactorCookieDays = parseInt('{{{twoFactorCookieDays}}}');
@@ -414,7 +417,7 @@
417
// Display the right server message
418
var i;
419
var messageid = parseInt('{{{messageid}}}');
417
- var okmessages = ['', "If valid, reset mail sent.", "Email sent.", "Email verification required, check your mailbox and click the confirmation link.", "SMS sent.", "Sending notification..."];
420
+ var okmessages = ['', "If valid, reset mail sent.", "Email sent.", "Email verification required, check your mailbox and click the confirmation link.", "SMS sent.", "Sending notification...", "Message sent."];
421
var failmessages = ["Unable to create account.", "Account limit reached.", "Existing account with this email address.", "Invalid account creation token.", "Username already exists.", "Password rejected, use a different one.", "Invalid email.", "Account not found.", "Invalid token, try again.", "Unable to sent email.", "Account locked.", "Access denied.", "Login failed, check username and password.", "Password change requested.", "IP address blocked, try again later.", "Server under maintenance.", "Unable to send device notification.", "Invalid security check."];
422
if (messageid > 0) {
423
var msg = '';
@@ -508,12 +511,14 @@
511
var twofakey = (hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn');
512
var emailkey = otpemail && (messageid != 2) && (messageid != 4);
513
var smskey = otpsms && (messageid != 2) && (messageid != 4);
514
+ var msgkey = otpmsg && (messageid != 2) && (messageid != 4);
515
var pushkey = otppush && (messageid != 2) && (messageid != 4);
516
QV('securityKeyButton', twofakey);
517
QV('emailKeyButton', emailkey);
518
QV('smsKeyButton', smskey);
519
+ QV('msgKeyButton', msgkey);
520
QV('pushKeyButton', pushkey);
516
- QV('2farow', twofakey || emailkey || smskey || pushkey);
521
+ QV('2farow', twofakey || emailkey || smskey || msgkey || pushkey);
522
523
// If hardware key is an option, trigger it now
524
if (autofido && twofakey) { setTimeout(function () { useSecurityKey(1); }, 300); }
@@ -525,12 +530,14 @@
530
var twofakey = (hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn');
531
var emailkey = otpemail && (messageid != 2) && (messageid != 4);
532
var smskey = otpsms && (messageid != 2) && (messageid != 4);
533
+ var msgkey = otpmsg && (messageid != 2) && (messageid != 4);
534
var pushkey = otppush && (messageid != 2) && (messageid != 4);
535
QV('securityKeyButton2', twofakey);
536
QV('emailKeyButton2', emailkey);
537
QV('smsKeyButton2', smskey);
538
+ QV('msgKeyButton2', msgkey);
539
QV('pushKeyButton', pushkey);
533
- QV('2farow2', twofakey || emailkey || smskey || pushkey);
540
+ QV('2farow2', twofakey || emailkey || smskey || msgkey || pushkey);
541
542
// If hardware key is an option, trigger it now
543
if (autofido && twofakey) { setTimeout(function () { useSecurityKey(2); }, 300); }
@@ -645,6 +652,23 @@
652
}
653
}
654
655
+ function useMsgToken(panelAction) {
656
+ if (otpmsg != true) return;
657
+ setDialogMode(1, "Secure Login", 3, useMsgTokenEx, "Send token to messaging application?", panelAction);
658
+ }
659
+
660
+ function useMsgTokenEx(b, panelAction) {
661
+ if (panelAction == 1) {
662
+ Q('hwtokenInput').value = '**msg**';
663
+ QE('tokenOkButton', true);
664
+ Q('tokenOkButton').click();
665
+ } else if (panelAction == 2) {
666
+ Q('resetHwtokenInput').value = '**msg**';
667
+ QE('resetTokenOkButton', true);
668
+ Q('resetTokenOkButton').click();
669
+ }
670
+ }
671
+
672
function usePushToken(panelAction) {
673
if (panelAction == 1) {
674
Q('hwtokenInput').value = '**push**';
webserver.js
+84
-8
@@ -892,8 +892,11 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
892
// See if SMS 2FA is available
893
var sms2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)) && (parent.smsserver != null) && (user.phone != null));
894
895
+ // See if Messenger 2FA is available
896
+ var msg2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.msg2factor != false)) && (parent.msgserver != null) && (parent.msgserver.providers != 0) && (user.msghandle != null));
897
+
898
// Check if a 2nd factor is present
896
- return ((parent.config.settings.no2factorauth !== true) && (sms2fa || (user.otpsecret != null) || ((user.email != null) && (user.emailVerified == true) && (domain.mailserver != null) && (user.otpekey != null)) || ((user.otphkeys != null) && (user.otphkeys.length > 0))));
899
+ return ((parent.config.settings.no2factorauth !== true) && (msg2fa || sms2fa || (user.otpsecret != null) || ((user.email != null) && (user.emailVerified == true) && (domain.mailserver != null) && (user.otpekey != null)) || ((user.otphkeys != null) && (user.otphkeys.length > 0))));
900
}
901
902
// Check the 2-step auth token
@@ -907,6 +910,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
910
if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.email2factor == false)) { otpemail = false; }
911
var otpsms = (parent.smsserver != null);
912
if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.sms2factor == false)) { otpsms = false; }
913
+ var otpmsg = ((parent.msgserver != null) && (parent.msgserver.providers != 0));
914
+ if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.msg2factor == false)) { otpmsg = false; }
915
916
// Check 2FA login cookie
917
if ((token != null) && (token.startsWith('cookie='))) {
@@ -926,7 +931,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
931
}
932
}
933
929
- // Check sms key
934
+ // Check SMS key
935
if ((otpsms) && (user.phone != null) && (user.otpsms != null) && (user.otpsms.d != null) && (user.otpsms.k === token)) {
936
var deltaTime = (Date.now() - user.otpsms.d);
937
if ((deltaTime > 0) && (deltaTime < 300000)) { // Allow 5 minutes to use the SMS token (10000 * 60 * 5).
@@ -938,6 +943,18 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
943
}
944
}
945
946
+ // Check messenger key
947
+ if ((otpmsg) && (user.msghandle != null) && (user.otpmsg != null) && (user.otpmsg.d != null) && (user.otpmsg.k === token)) {
948
+ var deltaTime = (Date.now() - user.otpmsg.d);
949
+ if ((deltaTime > 0) && (deltaTime < 300000)) { // Allow 5 minutes to use the Messenger token (10000 * 60 * 5).
950
+ delete user.otpmsg;
951
+ obj.db.SetUser(user);
952
+ parent.debug('web', 'checkUserOneTimePassword: success (Messenger).');
953
+ func(true, { twoFactorType: 'messenger' });
954
+ return;
955
+ }
956
+ }
957
+
958
// Check hardware key
959
if (user.otphkeys && (user.otphkeys.length > 0) && (typeof (hwtoken) == 'string') && (hwtoken.length > 0)) {
960
var authResponse = null;
@@ -1121,6 +1138,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
1138
1139
var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (domain.mailserver != null) && (user.email != null) && (user.emailVerified == true) && (user.otpekey != null));
1140
var sms2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)) && (parent.smsserver != null) && (user.phone != null));
1141
+ var msg2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.msg2factor != false)) && (parent.msgserver != null) && (parent.msgserver.providers != 0) && (user.msghandle != null));
1142
var push2fa = ((parent.firebase != null) && (user.otpdev != null));
1143
1144
// Check if two factor can be skipped
@@ -1158,6 +1176,19 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
1176
return;
1177
}
1178
1179
+ if ((req.body.hwtoken == '**msg**') && msg2fa) {
1180
+ // Cause a token to be sent to the user's messenger account
1181
+ user.otpmsg = { k: obj.common.zeroPad(getRandomSixDigitInteger(), 6), d: Date.now() };
1182
+ obj.db.SetUser(user);
1183
+ parent.debug('web', 'Sending 2FA message to: ' + user.msghandle);
1184
+ parent.msgserver.sendToken(domain, user.msghandle, user.otpmsg.k, obj.getLanguageCodes(req));
1185
+ // Ask for a login token & confirm message was sent
1186
+ req.session.messageid = 6; // "Message sent" message
1187
+ req.session.loginmode = 4;
1188
+ if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); }
1189
+ return;
1190
+ }
1191
+
1192
// Handle device push notification 2FA request
1193
// We create a browser cookie, send it back and when the browser connects it's web socket, it will trigger the push notification.
1194
if ((req.body.hwtoken == '**push**') && push2fa && ((domain.passwordrequirements == null) || (domain.passwordrequirements.push2factor != false))) {
@@ -1219,6 +1250,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
1250
req.session.loginmode = 4;
1251
if ((user.email != null) && (user.emailVerified == true) && (domain.mailserver != null) && (user.otpekey != null)) { req.session.temail = 1; }
1252
if ((user.phone != null) && (parent.smsserver != null)) { req.session.tsms = 1; }
1253
+ if ((user.msghandle != null) && (parent.msgserver != null) && (parent.msgserver.providers != 0)) { req.session.tmsg = 1; }
1254
if ((user.otpdev != null) && (parent.firebase != null)) { req.session.tpush = 1; }
1255
req.session.e = parent.encryptSessionData({ tuserid: userid, tuser: xusername, tpass: xpassword });
1256
if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); }
@@ -1358,6 +1390,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
1390
delete req.session.tpass;
1391
delete req.session.temail;
1392
delete req.session.tsms;
1393
+ delete req.session.tmsg;
1394
delete req.session.tpush;
1395
delete req.session.messageid;
1396
delete req.session.passhint;
@@ -1591,6 +1624,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
1624
delete req.session.tpass;
1625
delete req.session.temail;
1626
delete req.session.tsms;
1627
+ delete req.session.tmsg;
1628
delete req.session.tpush;
1629
delete req.session.messageid;
1630
delete req.session.passhint;
@@ -1673,6 +1707,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
1707
delete req.session.tpass;
1708
delete req.session.temail;
1709
delete req.session.tsms;
1710
+ delete req.session.tmsg;
1711
delete req.session.tpush;
1712
delete req.session.messageid;
1713
delete req.session.passhint;
@@ -1751,6 +1786,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
1786
parent.debug('web', 'handleResetAccountRequest: Invalid 2FA token, try again');
1787
if ((req.body.token != null) || (req.body.hwtoken != null)) {
1788
var sms2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)) && (parent.smsserver != null) && (user.phone != null));
1789
+ var msg2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.msg2factor != false)) && (parent.msgserver != null) && (parent.msgserver.providers != 0) && (user.msghandle != null));
1790
if ((req.body.hwtoken == '**sms**') && sms2fa) {
1791
// Cause a token to be sent to the user's phone number
1792
user.otpsms = { k: obj.common.zeroPad(getRandomSixDigitInteger(), 6), d: Date.now() };
@@ -1758,6 +1794,13 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
1794
parent.debug('web', 'Sending 2FA SMS for password recovery to: ' + user.phone);
1795
parent.smsserver.sendToken(domain, user.phone, user.otpsms.k, obj.getLanguageCodes(req));
1796
req.session.messageid = 4; // SMS sent.
1797
+ } else if ((req.body.hwtoken == '**msg**') && msg2fa) {
1798
+ // Cause a token to be sent to the user's messager account
1799
+ user.otpmsg = { k: obj.common.zeroPad(getRandomSixDigitInteger(), 6), d: Date.now() };
1800
+ obj.db.SetUser(user);
1801
+ parent.debug('web', 'Sending 2FA message for password recovery to: ' + user.msghandle);
1802
+ parent.msgserver.sendToken(domain, user.msghandle, user.otpmsg.k, obj.getLanguageCodes(req));
1803
+ req.session.messageid = 6; // Message sent.
1804
} else {
1805
req.session.messageid = 108; // Invalid token, try again.
1806
const ua = obj.getUserAgentInfo(req);
@@ -3204,6 +3247,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
3247
if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.email2factor == false)) { otpemail = false; }
3248
var otpsms = (parent.smsserver != null) && (req.session != null) && (req.session.tsms === 1);
3249
if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.sms2factor == false)) { otpsms = false; }
3250
+ var otpmsg = (parent.msgserver != null) && (req.session != null) && (req.session.tmsg === 1);
3251
+ if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.msg2factor == false)) { otpmsg = false; }
3252
var otppush = (parent.firebase != null) && (req.session != null) && (req.session.tpush === 1);
3253
if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.push2factor == false)) { otppush = false; }
3254
const autofido = ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.autofido2fa == true)); // See if FIDO should be automatically prompted if user account has it.
@@ -3270,6 +3315,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
3315
hwstate: hwstate,
3316
otpemail: otpemail,
3317
otpsms: otpsms,
3318
+ otpmsg: otpmsg,
3319
otppush: otppush,
3320
autofido: autofido,
3321
twoFactorCookieDays: twoFactorCookieDays,
@@ -7250,6 +7296,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
7296
// Figure out if email 2FA is allowed
7297
var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (domain.mailserver != null) && (user.otpekey != null));
7298
var sms2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)) && (parent.smsserver != null) && (user.phone != null));
7299
+ var msg2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.msg2factor != false)) && (parent.msgserver != null) && (parent.msgserver.providers != 0) && (user.msghandle != null));
7300
//var push2fa = ((parent.firebase != null) && (user.otpdev != null));
7301
if ((typeof command.token != 'string') || (command.token == '**email**') || (command.token == '**sms**')/* || (command.token == '**push**')*/) {
7302
if ((command.token == '**email**') && (email2fa == true)) {
@@ -7259,7 +7306,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
7306
parent.debug('web', 'Sending 2FA email to: ' + user.email);
7307
domain.mailserver.sendAccountLoginMail(domain, user.email, user.otpekey.k, obj.getLanguageCodes(req), req.query.key);
7308
// Ask for a login token & confirm email was sent
7262
- try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired', email2fa: email2fa, sms2fa: sms2fa, email2fasent: true, twoFactorCookieDays: twoFactorCookieDays })); ws.close(); } catch (e) { }
7309
+ try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired', email2fa: email2fa, sms2fa: sms2fa, msg2fa: msg2fa, email2fasent: true, twoFactorCookieDays: twoFactorCookieDays })); ws.close(); } catch (e) { }
7310
} else if ((command.token == '**sms**') && (sms2fa == true)) {
7311
// Cause a token to be sent to the user's phone number
7312
user.otpsms = { k: obj.common.zeroPad(getRandomSixDigitInteger(), 6), d: Date.now() };
@@ -7267,7 +7314,15 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
7314
parent.debug('web', 'Sending 2FA SMS to: ' + user.phone);
7315
parent.smsserver.sendToken(domain, user.phone, user.otpsms.k, obj.getLanguageCodes(req));
7316
// Ask for a login token & confirm sms was sent
7270
- try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired', email2fa: email2fa, sms2fa: sms2fa, sms2fasent: true, twoFactorCookieDays: twoFactorCookieDays })); ws.close(); } catch (e) { }
7317
+ try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired', email2fa: email2fa, sms2fa: sms2fa, msg2fa: msg2fa, sms2fasent: true, twoFactorCookieDays: twoFactorCookieDays })); ws.close(); } catch (e) { }
7318
+ } else if ((command.token == '**msg**') && (msg2fa == true)) {
7319
+ // Cause a token to be sent to the user's messenger account
7320
+ user.otpmsg = { k: obj.common.zeroPad(getRandomSixDigitInteger(), 6), d: Date.now() };
7321
+ obj.db.SetUser(user);
7322
+ parent.debug('web', 'Sending 2FA message to: ' + user.phone);
7323
+ parent.msgserver.sendToken(domain, user.msghandle, user.otpmsg.k, obj.getLanguageCodes(req));
7324
+ // Ask for a login token & confirm sms was sent
7325
+ try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired', email2fa: email2fa, sms2fa: sms2fa, msg2fa: msg2fa, msg2fasent: true, twoFactorCookieDays: twoFactorCookieDays })); ws.close(); } catch (e) { }
7326
/*
7327
} else if ((command.token == '**push**') && (push2fa == true)) {
7328
// Cause push notification to device
@@ -7311,7 +7366,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
7366
parent.debug('web', 'Invalid login, asking for email validation');
7367
var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (domain.mailserver != null) && (user.otpekey != null));
7368
var sms2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)) && (parent.smsserver != null) && (user.phone != null));
7314
- try { ws.send(JSON.stringify({ action: 'close', cause: 'emailvalidation', msg: 'emailvalidationrequired', email2fa: email2fa, sms2fa: sms2fa, email2fasent: true })); ws.close(); } catch (e) { }
7369
+ var msg2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.msg2factor != false)) && (parent.msgserver != null) && (parent.msgserver.providers != 0) && (user.msghandle != null));
7370
+ try { ws.send(JSON.stringify({ action: 'close', cause: 'emailvalidation', msg: 'emailvalidationrequired', email2fa: email2fa, sms2fa: sms2fa, msg2fa: msg2fa, email2fasent: true })); ws.close(); } catch (e) { }
7371
} else {
7372
// We are authenticated
7373
ws._socket.pause();
@@ -7396,6 +7452,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
7452
// Figure out if email 2FA is allowed
7453
var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (domain.mailserver != null) && (user.otpekey != null));
7454
var sms2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)) && (parent.smsserver != null) && (user.phone != null));
7455
+ var msg2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.msg2factor != false)) && (parent.msgserver != null) && (parent.msgserver.providers != 0) && (user.msghandle != null));
7456
//var push2fa = ((parent.firebase != null) && (user.otpdev != null));
7457
if ((typeof req.query.token != 'string') || (req.query.token == '**email**') || (req.query.token == '**sms**')/* || (req.query.token == '**push**')*/) {
7458
if ((req.query.token == '**email**') && (email2fa == true)) {
@@ -7405,7 +7462,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
7462
parent.debug('web', 'Sending 2FA email to: ' + user.email);
7463
domain.mailserver.sendAccountLoginMail(domain, user.email, user.otpekey.k, obj.getLanguageCodes(req), req.query.key);
7464
// Ask for a login token & confirm email was sent
7408
- try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired', email2fa: email2fa, sms2fa: sms2fa, email2fasent: true, twoFactorCookieDays: twoFactorCookieDays })); ws.close(); } catch (e) { }
7465
+ try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired', email2fa: email2fa, sms2fa: sms2fa, msg2fa: msg2fa, email2fasent: true, twoFactorCookieDays: twoFactorCookieDays })); ws.close(); } catch (e) { }
7466
} else if ((req.query.token == '**sms**') && (sms2fa == true)) {
7467
// Cause a token to be sent to the user's phone number
7468
user.otpsms = { k: obj.common.zeroPad(getRandomSixDigitInteger(), 6), d: Date.now() };
@@ -7413,7 +7470,15 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
7470
parent.debug('web', 'Sending 2FA SMS to: ' + user.phone);
7471
parent.smsserver.sendToken(domain, user.phone, user.otpsms.k, obj.getLanguageCodes(req));
7472
// Ask for a login token & confirm sms was sent
7416
- try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired', email2fa: email2fa, sms2fa: sms2fa, sms2fasent: true, twoFactorCookieDays: twoFactorCookieDays })); ws.close(); } catch (e) { }
7473
+ try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired', email2fa: email2fa, sms2fa: sms2fa, msg2fa: msg2fa, sms2fasent: true, twoFactorCookieDays: twoFactorCookieDays })); ws.close(); } catch (e) { }
7474
+ } else if ((req.query.token == '**msg**') && (msg2fa == true)) {
7475
+ // Cause a token to be sent to the user's messenger account
7476
+ user.otpmsg = { k: obj.common.zeroPad(getRandomSixDigitInteger(), 6), d: Date.now() };
7477
+ obj.db.SetUser(user);
7478
+ parent.debug('web', 'Sending 2FA message to: ' + user.msghandle);
7479
+ parent.msgserver.sendToken(domain, user.msghandle, user.otpmsg.k, obj.getLanguageCodes(req));
7480
+ // Ask for a login token & confirm message was sent
7481
+ try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired', email2fa: email2fa, sms2fa: sms2fa, msg2fa: msg2fa, msg2fasent: true, twoFactorCookieDays: twoFactorCookieDays })); ws.close(); } catch (e) { }
7482
/*
7483
} else if ((command.token == '**push**') && (push2fa == true)) {
7484
// Cause push notification to device
@@ -7454,7 +7519,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
7519
parent.debug('web', 'Invalid login, asking for email validation');
7520
var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (domain.mailserver != null) && (user.otpekey != null));
7521
var sms2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)) && (parent.smsserver != null) && (user.phone != null));
7457
- try { ws.send(JSON.stringify({ action: 'close', cause: 'emailvalidation', msg: 'emailvalidationrequired', email2fa: email2fa, sms2fa: sms2fa, email2fasent: true })); ws.close(); } catch (e) { }
7522
+ var msg2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.msg2factor != false)) && (parent.msgserver != null) && (parent.msgserver.providers != 0) && (user.msghandle != null));
7523
+ try { ws.send(JSON.stringify({ action: 'close', cause: 'emailvalidation', msg: 'emailvalidationrequired', email2fa: email2fa, sms2fa: sms2fa, msg2fa: msg2fa, email2fasent: true })); ws.close(); } catch (e) { }
7524
} else {
7525
// We are authenticated
7526
func(ws, req, domain, user);
@@ -7533,6 +7599,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
7599
// Figure out if email 2FA is allowed
7600
var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (domain.mailserver != null) && (user.otpekey != null));
7601
var sms2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)) && (parent.smsserver != null) && (user.phone != null));
7602
+ var msg2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.msg2factor != false)) && (parent.msgserver != null) && (parent.msgserver.providers != 0) && (user.msghandle != null));
7603
if (s.length != 3) {
7604
try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired', email2fa: email2fa, sms2fa: sms2fa, twoFactorCookieDays: twoFactorCookieDays })); ws.close(); } catch (e) { }
7605
} else {
@@ -7554,6 +7621,14 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
7621
parent.smsserver.sendToken(domain, user.phone, user.otpsms.k, obj.getLanguageCodes(req));
7622
// Ask for a login token & confirm sms was sent
7623
try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired', sms2fa: sms2fa, sms2fasent: true, twoFactorCookieDays: twoFactorCookieDays })); ws.close(); } catch (e) { }
7624
+ } else if ((s[2] == '**msg**') && (msg2fa == true)) {
7625
+ // Cause a token to be sent to the user's phone number
7626
+ user.otpmsg = { k: obj.common.zeroPad(getRandomSixDigitInteger(), 6), d: Date.now() };
7627
+ obj.db.SetUser(user);
7628
+ parent.debug('web', 'Sending 2FA message to: ' + user.msghandle);
7629
+ parent.msgserver.sendToken(domain, user.msghandle, user.otpmsg.k, obj.getLanguageCodes(req));
7630
+ // Ask for a login token & confirm sms was sent
7631
+ try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired', msg2fa: msg2fa, msg2fasent: true, twoFactorCookieDays: twoFactorCookieDays })); ws.close(); } catch (e) { }
7632
} else {
7633
// Ask for a login token
7634
try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired', email2fa: email2fa, twoFactorCookieDays: twoFactorCookieDays })); ws.close(); } catch (e) { }
@@ -8173,6 +8248,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
8248
delete user2.subscriptions;
8249
delete user2.passtype;
8250
delete user2.otpsms;
8251
+ delete user2.otpmsg;
8252
if ((typeof user2.otpekey == 'object') && (user2.otpekey != null)) { user2.otpekey = 1; } // Indicates that email 2FA is enabled.
8253
if ((typeof user2.otpsecret == 'string') && (user2.otpsecret != null)) { user2.otpsecret = 1; } // Indicates a time secret is present.
8254
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.