More work on mobile 2FA.

Ylian Saint-Hilaire committed Apr 13, 2021 at 23:23 UTC c74a20760634a91195f1a215203a44fd9a5d41b4
11 files changed +133 -10
MeshCentralServer.njsproj
+1
@@ -99,6 +99,7 @@
99 <Compile Include="amt\amt.js" />
100 <Compile Include="exeHandler.js" />
101 <Compile Include="amtprovisioningserver.js" />
102 + <Compile Include="firebase.js" />
103 <Compile Include="letsencrypt.js" />
104 <Compile Include="mcrec.js" />
105 <Compile Include="meshaccelerator.js" />
firebase.js
+26 -1
@@ -90,8 +90,16 @@ module.exports.CreateFirebase = function (parent, senderid, serverkey) {
90 //var payload = { notification: { title: command.title, body: command.msg }, data: { url: obj.msgurl } };
91 //var options = { priority: 'High', timeToLive: 5 * 60 }; // TTL: 5 minutes, priority 'Normal' or 'High'
92
93 - // Send an outbound push notification
93 obj.sendToDevice = function (node, payload, options, func) {
94 + if (typeof node == 'string') {
95 + parent.db.Get(node, function (err, docs) { if ((err == null) && (docs != null) && (docs.length == 1)) { obj.sendToDeviceEx(docs[0], payload, options, func); } else { func(0, 'error'); } })
96 + } else {
97 + obj.sendToDeviceEx(node, payload, options, func);
98 + }
99 + }
100 +
101 + // Send an outbound push notification
102 + obj.sendToDeviceEx = function (node, payload, options, func) {
103 parent.debug('email', 'Firebase-sendToDevice');
104 if ((node == null) || (typeof node.pmt != 'string')) return;
105 obj.log('sendToDevice, node:' + node._id + ', payload: ' + JSON.stringify(payload) + ', options: ' + JSON.stringify(options));
@@ -270,6 +278,14 @@ module.exports.CreateFirebaseRelay = function (parent, url, key) {
278 }
279
280 obj.sendToDevice = function (node, payload, options, func) {
281 + if (typeof node == 'string') {
282 + parent.db.Get(node, function (err, docs) { if ((err == null) && (docs != null) && (docs.length == 1)) { obj.sendToDeviceEx(docs[0], payload, options, func); } else { func(0, 'error'); } })
283 + } else {
284 + obj.sendToDeviceEx(node, payload, options, func);
285 + }
286 + }
287 +
288 + obj.sendToDeviceEx = function (node, payload, options, func) {
289 parent.debug('email', 'Firebase-sendToDevice-webSocket');
290 if ((node == null) || (typeof node.pmt != 'string')) { func(0, 'error'); return; }
291 obj.log('sendToDevice, node:' + node._id + ', payload: ' + JSON.stringify(payload) + ', options: ' + JSON.stringify(options));
@@ -298,7 +314,16 @@ module.exports.CreateFirebaseRelay = function (parent, url, key) {
314 } else if (relayUrl.protocol == 'https:') {
315 // Send an outbound push notification using an HTTPS POST
316 obj.pushOnly = true;
317 +
318 obj.sendToDevice = function (node, payload, options, func) {
319 + if (typeof node == 'string') {
320 + parent.db.Get(node, function (err, docs) { if ((err == null) && (docs != null) && (docs.length == 1)) { obj.sendToDeviceEx(docs[0], payload, options, func); } else { func(0, 'error'); } })
321 + } else {
322 + obj.sendToDeviceEx(node, payload, options, func);
323 + }
324 + }
325 +
326 + obj.sendToDeviceEx = function (node, payload, options, func) {
327 parent.debug('email', 'Firebase-sendToDevice-httpPost');
328 if ((node == null) || (typeof node.pmt != 'string')) return;
329
meshagent.js
+1
@@ -1556,6 +1556,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
1556 // Complete 2FA checking
1557 if (authCookie.a == 'checkAuth') {
1558 // TODO
1559 + console.log(authCookie);
1560 }
1561
1562 break;
public/images/login/2fa-push-48.png
Binary files /dev/null and b/public/images/login/2fa-push-48.png differ
public/images/login/2fa-push-96.png
Binary files /dev/null and b/public/images/login/2fa-push-96.png differ
public/images/login/push-150.png
Binary files /dev/null and b/public/images/login/push-150.png differ
public/images/login/push-300.png
Binary files /dev/null and b/public/images/login/push-300.png differ
public/styles/style.css
+1 -1
@@ -394,7 +394,7 @@ body {
394 color: blue;
395 }
396
397 -#loginpanel, #createpanel, #resetpanel, #tokenpanel, #resettokenpanel, #resetpasswordpanel, #resetpasswordpanel, #checkemailpanel {
397 +#loginpanel, #createpanel, #resetpanel, #tokenpanel, #resettokenpanel, #resetpasswordpanel, #resetpasswordpanel, #checkemailpanel, #waitpushpanel {
398 display: inline-block;
399 margin: 0;
400 background-color: #979797;
views/default.handlebars
+1
@@ -2032,6 +2032,7 @@
2032 QV('authKeySetupCheck', userinfo.otphkeys > 0);
2033 QV('authPushAuthDevCheck', (userinfo.otpdev > 0) && ((features2 & 2) != 0));
2034 QV('authCodesSetupCheck', userinfo.otpkeys > 0);
2035 + QV('managePushAuthDev', (features2 & 2) && (count2factoraAuths() > 0));
2036 mainUpdate(4 + 128 + 4096);
2037
2038 // Check if none or at least 2 factors are enabled.
views/login2.handlebars
+45 -5
@@ -186,6 +186,7 @@
186 <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)" />
187 <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)" />
188 <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)" />
189 + <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)" />
190 </div>
191 </td>
192 </tr>
@@ -219,6 +220,7 @@
220 <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)" />
221 <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)" />
222 <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)" />
223 + <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)" />
224 </div>
225 </td>
226 </tr>
@@ -281,6 +283,22 @@
283 <input id=checkemailformargs name="urlargs" type="hidden" value="" />
284 </form>
285 </div>
286 + <div id=waitpushpanel style="display:none">
287 + <div id=message8></div>
288 + <table style="width:100%">
289 + <tr>
290 + <td style="align-content:center;padding-top:10px">
291 + <img src="images/login/push-150.png" srcset="images/login/push-300.png 2x" loading="lazy" width="265" height="150" />
292 + </td>
293 + </tr>
294 + <tr>
295 + <td style="align-content:center;padding-top:10px">
296 + <label id=tokenInputRememberLabel2><input id=tokenInputRemember2 name=remembertoken type=checkbox /><span id=tokenInputRememberSpan2></span></label>
297 + </td>
298 + </tr>
299 + </table>
300 + <hr /><a onclick="return xgo(1,event);" href="#" style=cursor:pointer>Back to login</a>
301 + </div>
302 </td>
303 </tr>
304 <tr id="welcomeTextRow"><td><div id="welcomeText" style="color:white;text-align:center;margin-left:20px;margin-right:20px"></div></td></tr>
@@ -330,6 +348,7 @@
348 var publicKeyCredentialRequestOptions = null;
349 var otpemail = (decodeURIComponent('{{{otpemail}}}') === 'true');
350 var otpsms = (decodeURIComponent('{{{otpsms}}}') === 'true');
351 + var otppush = (decodeURIComponent('{{{otppush}}}') === 'true');
352 var twoFactorCookieDays = parseInt('{{{twoFactorCookieDays}}}');
353 var authStrategies = '{{{authStrategies}}}'.split(',');
354
@@ -342,15 +361,16 @@
361 // Display the right server message
362 var i;
363 var messageid = parseInt('{{{messageid}}}');
345 - var okmessages = ['', "If valid, reset mail sent.", "Email sent.", "Email verification required, check your mailbox and click the confirmation link.", "SMS sent."];
346 - 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."];
364 + var okmessages = ['', "If valid, reset mail sent.", "Email sent.", "Email verification required, check your mailbox and click the confirmation link.", "SMS sent.", "Notification sent, {0}."];
365 + 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."];
366 if (messageid > 0) {
367 var msg = '';
368 if ((messageid < 100) && (messageid < okmessages.length)) { msg = okmessages[messageid]; }
369 else if ((messageid >= 100) && ((messageid - 100) < failmessages.length)) { msg = failmessages[messageid - 100]; }
370 + if (messageid == 5) { msg = format(msg, passhint); }
371 if (msg != '') {
372 if (messageid >= 100) { msg = ('<span class="msg error"><b style=color:#8C001A>' + msg + '<b></span><br /><br />'); } else { msg = ('<span class="msg success"><b>' + msg + '</b></span><br /><br />'); }
353 - for (i = 1; i < 8; i++) { QH('message' + i, msg); }
373 + for (i = 1; i < 9; i++) { QH('message' + i, msg); }
374 }
375 }
376
@@ -369,8 +389,11 @@
389 if (twoFactorCookieDays > 0) {
390 QV('tokenInputRememberLabel', true);
391 QH('tokenInputRememberSpan', format("Remember this device for {0} days.", twoFactorCookieDays));
392 + QV('tokenInputRememberLabel2', true);
393 + QH('tokenInputRememberSpan2', format("Remember this device for {0} days.", twoFactorCookieDays));
394 } else {
395 QV('tokenInputRememberLabel', false);
396 + QV('tokenInputRememberLabel2', false);
397 }
398
399 // If URL arguments are provided, add them to form posts
@@ -443,10 +466,12 @@
466 var twofakey = (hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn');
467 var emailkey = otpemail && (messageid != 2) && (messageid != 4);
468 var smskey = otpsms && (messageid != 2) && (messageid != 4);
469 + var pushkey = otppush && (messageid != 2) && (messageid != 4);
470 QV('securityKeyButton', twofakey);
471 QV('emailKeyButton', emailkey);
472 QV('smsKeyButton', smskey);
449 - QV('2farow', twofakey || emailkey || smskey);
473 + QV('pushKeyButton', pushkey);
474 + QV('2farow', twofakey || emailkey || smskey || pushkey);
475 }
476
477 if (loginMode == '5') {
@@ -454,10 +479,12 @@
479 var twofakey = (hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn');
480 var emailkey = otpemail && (messageid != 2) && (messageid != 4);
481 var smskey = otpsms && (messageid != 2) && (messageid != 4);
482 + var pushkey = otppush && (messageid != 2) && (messageid != 4);
483 QV('securityKeyButton2', twofakey);
484 QV('emailKeyButton2', emailkey);
485 QV('smsKeyButton2', smskey);
460 - QV('2farow2', twofakey || emailkey || smskey);
486 + QV('pushKeyButton', pushkey);
487 + QV('2farow2', twofakey || emailkey || smskey || pushkey);
488 }
489
490 /*
@@ -565,6 +592,18 @@
592 }
593 }
594
595 + function usePushToken(panelAction) {
596 + if (panelAction == 1) {
597 + Q('hwtokenInput').value = '**push**';
598 + QE('tokenOkButton', true);
599 + Q('tokenOkButton').click();
600 + } else if (panelAction == 2) {
601 + Q('resetHwtokenInput').value = '**push**';
602 + QE('resetTokenOkButton', true);
603 + Q('resetTokenOkButton').click();
604 + }
605 + }
606 +
607 function showPassHint(e) {
608 messagebox("Password Hint", passhint);
609 haltEvent(e);
@@ -595,6 +634,7 @@
634 QV('resettokenpanel', x == 5);
635 QV('resetpasswordpanel', x == 6);
636 QV('checkemailpanel', x == 7);
637 + QV('waitpushpanel', x == 8);
638 if (x == 1) { Q('username').focus(); }
639 if (x == 2) { if (features & 0x200000) { Q('aemail').focus(); } else { Q('ausername').focus(); } } // Email is username
640 if (x == 3) { Q('remail').focus(); }
webserver.js
+58 -3
@@ -924,6 +924,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
924
925 var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (domain.mailserver != null) && (user.email != null) && (user.emailVerified == true) && (user.otpekey != null));
926 var sms2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)) && (parent.smsserver != null) && (user.phone != null));
927 + var push2fa = ((parent.firebase != null) && (user.otpdev != null));
928
929 // Check if this user has 2-step login active
930 if ((req.session.loginmode != '6') && checkUserOneTimePasswordRequired(domain, user, req)) {
@@ -951,6 +952,29 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
952 return;
953 }
954
955 + if ((req.body.hwtoken == '**push**') && push2fa) {
956 + // Cause push notification to device
957 + const logincode = obj.common.zeroPad(getRandomSixDigitInteger(), 6);
958 + const code = Buffer.from(logincode).toString('base64');
959 + const authCookie = parent.encodeCookie({ a: 'checkAuth', c: code, u: user._id, n: user.otpdev });
960 + var payload = { notification: { title: "MeshCentral", body: user.name + " authentication" }, data: { url: '2fa://auth?code=' + code + '&c=' + authCookie } };
961 + var options = { priority: 'High', timeToLive: 60 }; // TTL: 1 minute
962 + parent.firebase.sendToDevice(user.otpdev, payload, options, function (id, err, errdesc) {
963 + if (err == null) {
964 + // Request that the login page wait for device auth
965 + req.session.messageid = 5; // "Notification sent." message
966 + req.session.passhint = logincode;
967 + req.session.loginmode = '8';
968 + } else {
969 + // Indicate the push notification failed
970 + req.session.messageid = 116; // "Unable to send device notification." message
971 + req.session.loginmode = '4';
972 + }
973 + if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); }
974 + });
975 + return;
976 + }
977 +
978 checkUserOneTimePassword(req, domain, user, req.body.token, req.body.hwtoken, function (result) {
979 if (result == false) {
980 var randomWaitTime = 0;
@@ -973,6 +997,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
997 req.session.loginmode = '4';
998 req.session.tokenemail = ((user.email != null) && (user.emailVerified == true) && (domain.mailserver != null) && (user.otpekey != null));
999 req.session.tokensms = ((user.phone != null) && (parent.smsserver != null));
1000 + req.session.tokenpush = ((user.otpdev != null) && (parent.firebase != null));
1001 req.session.tokenuserid = userid;
1002 req.session.tokenusername = xusername;
1003 req.session.tokenpassword = xpassword;
@@ -1097,6 +1122,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1122 delete req.session.tokenpassword;
1123 delete req.session.tokenemail;
1124 delete req.session.tokensms;
1125 + delete req.session.tokenpush;
1126 delete req.session.messageid;
1127 delete req.session.passhint;
1128 delete req.session.cuserid;
@@ -1301,6 +1327,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1327 delete req.session.resettokenpassword;
1328 delete req.session.tokenemail;
1329 delete req.session.tokensms;
1330 + delete req.session.tokenpush;
1331 delete req.session.messageid;
1332 delete req.session.passhint;
1333 delete req.session.cuserid;
@@ -1382,6 +1409,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1409 delete req.session.resettokenpassword;
1410 delete req.session.tokenemail;
1411 delete req.session.tokensms;
1412 + delete req.session.tokenpush;
1413 delete req.session.messageid;
1414 delete req.session.passhint;
1415 delete req.session.cuserid;
@@ -2638,7 +2666,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2666 var passhint = null, msgid = 0;
2667 if (req.session != null) {
2668 msgid = req.session.messageid;
2641 - if ((loginmode == '7') || ((domain.passwordrequirements != null) && (domain.passwordrequirements.hint === true))) { passhint = EscapeHtml(req.session.passhint); }
2669 + if ((msgid == 5) || (loginmode == '7') || ((domain.passwordrequirements != null) && (domain.passwordrequirements.hint === true))) { passhint = EscapeHtml(req.session.passhint); }
2670 delete req.session.messageid;
2671 delete req.session.passhint;
2672 }
@@ -2658,6 +2686,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2686 if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.email2factor == false)) { otpemail = false; }
2687 var otpsms = (parent.smsserver != null) && (req.session != null) && (req.session.tokensms == true);
2688 if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.sms2factor == false)) { otpsms = false; }
2689 + var otppush = (parent.firebase != null) && (req.session != null) && (req.session.tokenpush == true);
2690 + //if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.push2factor == false)) { otppush = false; }
2691
2692 // See if we support two-factor trusted cookies
2693 var twoFactorCookieDays = 30;
@@ -2704,6 +2734,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2734 hwstate: hwstate,
2735 otpemail: otpemail,
2736 otpsms: otpsms,
2737 + otppush: otppush,
2738 twoFactorCookieDays: twoFactorCookieDays,
2739 authStrategies: authStrategies.join(','),
2740 loginpicture: (typeof domain.loginpicture == 'string')
@@ -5844,7 +5875,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
5875 // Figure out if email 2FA is allowed
5876 var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (domain.mailserver != null) && (user.otpekey != null));
5877 var sms2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)) && (parent.smsserver != null) && (user.phone != null));
5847 - if ((typeof command.token != 'string') || (command.token == '**email**') || (command.token == '**sms**')) {
5878 + //var push2fa = ((parent.firebase != null) && (user.otpdev != null));
5879 + if ((typeof command.token != 'string') || (command.token == '**email**') || (command.token == '**sms**')/* || (command.token == '**push**')*/) {
5880 if ((command.token == '**email**') && (email2fa == true)) {
5881 // Cause a token to be sent to the user's registered email
5882 user.otpekey = { k: obj.common.zeroPad(getRandomEightDigitInteger(), 8), d: Date.now() };
@@ -5861,6 +5893,17 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
5893 parent.smsserver.sendToken(domain, user.phone, user.otpsms.k, obj.getLanguageCodes(req));
5894 // Ask for a login token & confirm sms was sent
5895 try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired', email2fa: email2fa, sms2fa: sms2fa, sms2fasent: true, twoFactorCookieDays: twoFactorCookieDays })); ws.close(); } catch (e) { }
5896 + /*
5897 + } else if ((command.token == '**push**') && (push2fa == true)) {
5898 + // Cause push notification to device
5899 + const code = Buffer.from(obj.common.zeroPad(getRandomSixDigitInteger(), 6)).toString('base64');
5900 + const authCookie = parent.encodeCookie({ a: 'checkAuth', c: code, u: user._id, n: user.otpdev });
5901 + var payload = { notification: { title: "MeshCentral", body: user.name + " authentication" }, data: { url: '2fa://auth?code=' + code + '&c=' + authCookie } };
5902 + var options = { priority: 'High', timeToLive: 60 }; // TTL: 1 minute
5903 + parent.firebase.sendToDevice(user.otpdev, payload, options, function (id, err, errdesc) {
5904 + if (err == null) { parent.debug('email', 'Successfully auth check send push message to device'); } else { parent.debug('email', 'Failed auth check push message to device, error: ' + errdesc); }
5905 + });
5906 + */
5907 } else {
5908 // Ask for a login token
5909 parent.debug('web', 'Asking for login token');
@@ -5965,7 +6008,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
6008 // Figure out if email 2FA is allowed
6009 var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (domain.mailserver != null) && (user.otpekey != null));
6010 var sms2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)) && (parent.smsserver != null) && (user.phone != null));
5968 - if ((typeof req.query.token != 'string') || (req.query.token == '**email**') || (req.query.token == '**sms**')) {
6011 + //var push2fa = ((parent.firebase != null) && (user.otpdev != null));
6012 + if ((typeof req.query.token != 'string') || (req.query.token == '**email**') || (req.query.token == '**sms**')/* || (req.query.token == '**push**')*/) {
6013 if ((req.query.token == '**email**') && (email2fa == true)) {
6014 // Cause a token to be sent to the user's registered email
6015 user.otpekey = { k: obj.common.zeroPad(getRandomEightDigitInteger(), 8), d: Date.now() };
@@ -5982,6 +6026,17 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
6026 parent.smsserver.sendToken(domain, user.phone, user.otpsms.k, obj.getLanguageCodes(req));
6027 // Ask for a login token & confirm sms was sent
6028 try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired', email2fa: email2fa, sms2fa: sms2fa, sms2fasent: true, twoFactorCookieDays: twoFactorCookieDays })); ws.close(); } catch (e) { }
6029 + /*
6030 + } else if ((command.token == '**push**') && (push2fa == true)) {
6031 + // Cause push notification to device
6032 + const code = Buffer.from(obj.common.zeroPad(getRandomSixDigitInteger(), 6)).toString('base64');
6033 + const authCookie = parent.encodeCookie({ a: 'checkAuth', c: code, u: user._id, n: user.otpdev });
6034 + var payload = { notification: { title: "MeshCentral", body: user.name + " authentication" }, data: { url: '2fa://auth?code=' + code + '&c=' + authCookie } };
6035 + var options = { priority: 'High', timeToLive: 60 }; // TTL: 1 minute
6036 + parent.firebase.sendToDevice(user.otpdev, payload, options, function (id, err, errdesc) {
6037 + if (err == null) { parent.debug('email', 'Successfully auth check send push message to device'); } else { parent.debug('email', 'Failed auth check push message to device, error: ' + errdesc); }
6038 + });
6039 + */
6040 } else {
6041 // Ask for a login token
6042 parent.debug('web', 'Asking for login token');