Skip to content

Commit

Permalink
Added support for 2FA messaging (#4650)
Browse files Browse the repository at this point in the history
  • Loading branch information
Ylianst committed Oct 22, 2022
1 parent c62bc9c commit e2cf723
Show file tree
Hide file tree
Showing 8 changed files with 139 additions and 13 deletions.
2 changes: 1 addition & 1 deletion meshmessaging.js
Expand Up @@ -69,7 +69,7 @@ module.exports.CreateServer = function (parent) {
async function sendTelegramMessage(to, msg, func) {
if (obj.telegramClient == null) return;
parent.debug('email', 'Sending Telegram message to: ' + to.substring(9) + ': ' + msg);
try { await obj.telegramClient.sendMessage(to.substring(9), { message: msg }); func(true); } catch (ex) { func(false, ex); }
try { await obj.telegramClient.sendMessage(to.substring(9), { message: msg }); if (func != null) { func(true); } } catch (ex) { if (func != null) { func(false, ex); } }
}
sendTelegramMessage(to, msg, func);
} else {
Expand Down
2 changes: 2 additions & 0 deletions meshuser.js
Expand Up @@ -7941,10 +7941,12 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
function count2factoraAuths() {
var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (domain.mailserver != null));
var sms2fa = ((parent.parent.smsserver != null) && ((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)));
var msg2fa = ((parent.parent.msgserver != null) && (parent.parent.msgserver.providers != 0) && ((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.msg2factor != false)));
var authFactorCount = 0;
if (typeof user.otpsecret == 'string') { authFactorCount++; } // Authenticator time factor
if (email2fa && (user.otpekey != null)) { authFactorCount++; } // EMail factor
if (sms2fa && (user.phone != null)) { authFactorCount++; } // SMS factor
if (msg2fa && (user.msghandle != null)) { authFactorCount++; } // Messaging factor
if (user.otphkeys != null) { authFactorCount += user.otphkeys.length; } // FIDO hardware factor
if ((authFactorCount > 0) && (user.otpkeys != null)) { authFactorCount++; } // Backup keys
return authFactorCount;
Expand Down
Binary file added public/images/login/2fa-messaging-48.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/login/2fa-messaging-96.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions views/default.handlebars
Expand Up @@ -2230,6 +2230,7 @@
if (userinfo.otphkeys > 0) { authFactorCount += userinfo.otphkeys; } // FIDO hardware factor
if ((features & 0x00800000) && (userinfo.otpekey == 1)) { authFactorCount++; } // EMail factor
if ((features & 0x02000000) && (features & 0x04000000) && (userinfo.phone != null)) { authFactorCount++; } // SMS factor
if ((features2 & 0x02000000) && (features2 & 0x04000000) && (userinfo.msghandle != null)) { authFactorCount++; } // Messaging factor
if ((authFactorCount > 0) && (userinfo.otpkeys > 0) && ((features2 & 0x40000) == 0)) { authFactorCount++; } // Backup keys
return authFactorCount;
}
Expand Down Expand Up @@ -16738,6 +16739,7 @@
if (v == 'fido') { return "FIDO key"; }
if (v == 'sms') { return "SMS message"; }
if (v == 'hwotp') { return "Hardware OTP"; }
if (v == 'messenger') { return "Messenging"; }
if (v == 'push') { return "Push Notification"; }
if (v == 'otp') { return "One-Time Password"; }
if (v == 'cookie') { return "Remember Device"; }
Expand Down
24 changes: 23 additions & 1 deletion views/login.handlebars
Expand Up @@ -190,6 +190,7 @@
<input style="display:none;float:right" id=securityKeyButton type=button value="Use Security Key" onclick="useSecurityKey(1)" />
<input style="display:none;float:right" id=emailKeyButton type=button value="Email" onclick="useEmailToken(1)" />
<input style="display:none;float:right" id=smsKeyButton type=button value="SMS" onclick="useSMSToken(1)" />
<input style="display:none;float:right" id=msgKeyButton type=button value="Messaging" onclick="useMsgToken(1)" />
</div>
</td>
</tr>
Expand Down Expand Up @@ -217,6 +218,7 @@
<input style="display:none;float:right" id=securityKeyButton2 type=button value="Use Security Key" onclick="useSecurityKey(2)" />
<input style="display:none;float:right" id=emailKeyButton2 type=button value="Email" onclick="useEmailToken(2)" />
<input style="display:none;float:right" id=smsKeyButton2 type=button value="SMS" onclick="useSMSToken(2)" />
<input style="display:none;float:right" id=msgKeyButton2 type=button value="Messaging" onclick="useMsgToken(2)" />
</div>
</td>
</tr>
Expand Down Expand Up @@ -335,6 +337,7 @@
var publicKeyCredentialRequestOptions = null;
var otpemail = (decodeURIComponent('{{{otpemail}}}') === 'true');
var otpsms = (decodeURIComponent('{{{otpsms}}}') === 'true');
var otpmsg = (decodeURIComponent('{{{otpmsg}}}') === 'true');
var autofido = (decodeURIComponent('{{{autofido}}}') === 'true');
var twoFactorCookieDays = parseInt('{{{twoFactorCookieDays}}}');
var authStrategies = '{{{authStrategies}}}'.split(',');
Expand All @@ -344,7 +347,7 @@
// Display the right server message
var i;
var messageid = parseInt('{{{messageid}}}');
var okmessages = ['', "If valid, reset mail sent.", "Email sent.", "Email verification required, check your mailbox and click the confirmation link.", "SMS sent."];
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."];
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."];
if (messageid > 0) {
var msg = '';
Expand Down Expand Up @@ -455,6 +458,7 @@
QV('securityKeyButton', twofakey);
QV('emailKeyButton', otpemail && (messageid != 2) && (messageid != 4));
QV('smsKeyButton', otpsms && (messageid != 2) && (messageid != 4));
QV('msgKeyButton', otpmsg && (messageid != 2) && (messageid != 4));
// If hardware key is an option, trigger it now
if (autofido && twofakey) { setTimeout(function () { useSecurityKey(1); }, 300); }
Expand All @@ -467,6 +471,7 @@
QV('securityKeyButton2', twofakey);
QV('emailKeyButton2', otpemail && (messageid != 2) && (messageid != 4));
QV('smsKeyButton2', otpsms && (messageid != 2) && (messageid != 4));
QV('msgKeyButton2', otpmsg && (messageid != 2) && (messageid != 4));
// If hardware key is an option, trigger it now
if (autofido && twofakey) { setTimeout(function () { useSecurityKey(2); }, 300); }
Expand Down Expand Up @@ -580,6 +585,23 @@
}
}
function useMsgToken(panelAction) {
if (otpmsg != true) return;
setDialogMode(1, "Secure Login", 3, useMsgTokenEx, "Send token to messaging application?", panelAction);
}
function useMsgTokenEx(b, panelAction) {
if (panelAction == 1) {
Q('hwtokenInput').value = '**msg**';
QE('tokenOkButton', true);
Q('tokenOkButton').click();
} else if (panelAction == 2) {
Q('resetHwtokenInput').value = '**msg**';
QE('resetTokenOkButton', true);
Q('resetTokenOkButton').click();
}
}
function showPassHint(e) {
messagebox("Password Hint", passhint);
haltEvent(e);
Expand Down
30 changes: 27 additions & 3 deletions views/login2.handlebars
Expand Up @@ -217,6 +217,7 @@
<div>
<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)" />
<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)" />
<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)" />
<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)" />
<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)" />
</div>
Expand Down Expand Up @@ -251,6 +252,7 @@
<div>
<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)" />
<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)" />
<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)" />
<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)" />
<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)" />
</div>
Expand Down Expand Up @@ -389,6 +391,7 @@
var publicKeyCredentialRequestOptions = null;
var otpemail = (decodeURIComponent('{{{otpemail}}}') === 'true');
var otpsms = (decodeURIComponent('{{{otpsms}}}') === 'true');
var otpmsg = (decodeURIComponent('{{{otpmsg}}}') === 'true');
var otppush = (decodeURIComponent('{{{otppush}}}') === 'true');
var autofido = (decodeURIComponent('{{{autofido}}}') === 'true');
var twoFactorCookieDays = parseInt('{{{twoFactorCookieDays}}}');
Expand All @@ -414,7 +417,7 @@
// Display the right server message
var i;
var messageid = parseInt('{{{messageid}}}');
var okmessages = ['', "If valid, reset mail sent.", "Email sent.", "Email verification required, check your mailbox and click the confirmation link.", "SMS sent.", "Sending notification..."];
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."];
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."];
if (messageid > 0) {
var msg = '';
Expand Down Expand Up @@ -508,12 +511,14 @@
var twofakey = (hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn');
var emailkey = otpemail && (messageid != 2) && (messageid != 4);
var smskey = otpsms && (messageid != 2) && (messageid != 4);
var msgkey = otpmsg && (messageid != 2) && (messageid != 4);
var pushkey = otppush && (messageid != 2) && (messageid != 4);
QV('securityKeyButton', twofakey);
QV('emailKeyButton', emailkey);
QV('smsKeyButton', smskey);
QV('msgKeyButton', msgkey);
QV('pushKeyButton', pushkey);
QV('2farow', twofakey || emailkey || smskey || pushkey);
QV('2farow', twofakey || emailkey || smskey || msgkey || pushkey);
// If hardware key is an option, trigger it now
if (autofido && twofakey) { setTimeout(function () { useSecurityKey(1); }, 300); }
Expand All @@ -525,12 +530,14 @@
var twofakey = (hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn');
var emailkey = otpemail && (messageid != 2) && (messageid != 4);
var smskey = otpsms && (messageid != 2) && (messageid != 4);
var msgkey = otpmsg && (messageid != 2) && (messageid != 4);
var pushkey = otppush && (messageid != 2) && (messageid != 4);
QV('securityKeyButton2', twofakey);
QV('emailKeyButton2', emailkey);
QV('smsKeyButton2', smskey);
QV('msgKeyButton2', msgkey);
QV('pushKeyButton', pushkey);
QV('2farow2', twofakey || emailkey || smskey || pushkey);
QV('2farow2', twofakey || emailkey || smskey || msgkey || pushkey);
// If hardware key is an option, trigger it now
if (autofido && twofakey) { setTimeout(function () { useSecurityKey(2); }, 300); }
Expand Down Expand Up @@ -645,6 +652,23 @@
}
}
function useMsgToken(panelAction) {
if (otpmsg != true) return;
setDialogMode(1, "Secure Login", 3, useMsgTokenEx, "Send token to messaging application?", panelAction);
}
function useMsgTokenEx(b, panelAction) {
if (panelAction == 1) {
Q('hwtokenInput').value = '**msg**';
QE('tokenOkButton', true);
Q('tokenOkButton').click();
} else if (panelAction == 2) {
Q('resetHwtokenInput').value = '**msg**';
QE('resetTokenOkButton', true);
Q('resetTokenOkButton').click();
}
}
function usePushToken(panelAction) {
if (panelAction == 1) {
Q('hwtokenInput').value = '**push**';
Expand Down

0 comments on commit e2cf723

Please sign in to comment.