mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2025-02-12 11:01:52 +00:00
More work on mobile 2FA.
This commit is contained in:
parent
da33f1dfb1
commit
c74a207606
11 changed files with 133 additions and 10 deletions
|
@ -99,6 +99,7 @@
|
||||||
<Compile Include="amt\amt.js" />
|
<Compile Include="amt\amt.js" />
|
||||||
<Compile Include="exeHandler.js" />
|
<Compile Include="exeHandler.js" />
|
||||||
<Compile Include="amtprovisioningserver.js" />
|
<Compile Include="amtprovisioningserver.js" />
|
||||||
|
<Compile Include="firebase.js" />
|
||||||
<Compile Include="letsencrypt.js" />
|
<Compile Include="letsencrypt.js" />
|
||||||
<Compile Include="mcrec.js" />
|
<Compile Include="mcrec.js" />
|
||||||
<Compile Include="meshaccelerator.js" />
|
<Compile Include="meshaccelerator.js" />
|
||||||
|
|
27
firebase.js
27
firebase.js
|
@ -90,8 +90,16 @@ module.exports.CreateFirebase = function (parent, senderid, serverkey) {
|
||||||
//var payload = { notification: { title: command.title, body: command.msg }, data: { url: obj.msgurl } };
|
//var payload = { notification: { title: command.title, body: command.msg }, data: { url: obj.msgurl } };
|
||||||
//var options = { priority: 'High', timeToLive: 5 * 60 }; // TTL: 5 minutes, priority 'Normal' or 'High'
|
//var options = { priority: 'High', timeToLive: 5 * 60 }; // TTL: 5 minutes, priority 'Normal' or 'High'
|
||||||
|
|
||||||
// Send an outbound push notification
|
|
||||||
obj.sendToDevice = function (node, payload, options, func) {
|
obj.sendToDevice = function (node, payload, options, func) {
|
||||||
|
if (typeof node == 'string') {
|
||||||
|
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'); } })
|
||||||
|
} else {
|
||||||
|
obj.sendToDeviceEx(node, payload, options, func);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send an outbound push notification
|
||||||
|
obj.sendToDeviceEx = function (node, payload, options, func) {
|
||||||
parent.debug('email', 'Firebase-sendToDevice');
|
parent.debug('email', 'Firebase-sendToDevice');
|
||||||
if ((node == null) || (typeof node.pmt != 'string')) return;
|
if ((node == null) || (typeof node.pmt != 'string')) return;
|
||||||
obj.log('sendToDevice, node:' + node._id + ', payload: ' + JSON.stringify(payload) + ', options: ' + JSON.stringify(options));
|
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) {
|
||||||
}
|
}
|
||||||
|
|
||||||
obj.sendToDevice = function (node, payload, options, func) {
|
obj.sendToDevice = function (node, payload, options, func) {
|
||||||
|
if (typeof node == 'string') {
|
||||||
|
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'); } })
|
||||||
|
} else {
|
||||||
|
obj.sendToDeviceEx(node, payload, options, func);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.sendToDeviceEx = function (node, payload, options, func) {
|
||||||
parent.debug('email', 'Firebase-sendToDevice-webSocket');
|
parent.debug('email', 'Firebase-sendToDevice-webSocket');
|
||||||
if ((node == null) || (typeof node.pmt != 'string')) { func(0, 'error'); return; }
|
if ((node == null) || (typeof node.pmt != 'string')) { func(0, 'error'); return; }
|
||||||
obj.log('sendToDevice, node:' + node._id + ', payload: ' + JSON.stringify(payload) + ', options: ' + JSON.stringify(options));
|
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) {
|
||||||
} else if (relayUrl.protocol == 'https:') {
|
} else if (relayUrl.protocol == 'https:') {
|
||||||
// Send an outbound push notification using an HTTPS POST
|
// Send an outbound push notification using an HTTPS POST
|
||||||
obj.pushOnly = true;
|
obj.pushOnly = true;
|
||||||
|
|
||||||
obj.sendToDevice = function (node, payload, options, func) {
|
obj.sendToDevice = function (node, payload, options, func) {
|
||||||
|
if (typeof node == 'string') {
|
||||||
|
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'); } })
|
||||||
|
} else {
|
||||||
|
obj.sendToDeviceEx(node, payload, options, func);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.sendToDeviceEx = function (node, payload, options, func) {
|
||||||
parent.debug('email', 'Firebase-sendToDevice-httpPost');
|
parent.debug('email', 'Firebase-sendToDevice-httpPost');
|
||||||
if ((node == null) || (typeof node.pmt != 'string')) return;
|
if ((node == null) || (typeof node.pmt != 'string')) return;
|
||||||
|
|
||||||
|
|
|
@ -1556,6 +1556,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||||
// Complete 2FA checking
|
// Complete 2FA checking
|
||||||
if (authCookie.a == 'checkAuth') {
|
if (authCookie.a == 'checkAuth') {
|
||||||
// TODO
|
// TODO
|
||||||
|
console.log(authCookie);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
BIN
public/images/login/2fa-push-48.png
Normal file
BIN
public/images/login/2fa-push-48.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.8 KiB |
BIN
public/images/login/2fa-push-96.png
Normal file
BIN
public/images/login/2fa-push-96.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
BIN
public/images/login/push-150.png
Normal file
BIN
public/images/login/push-150.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 32 KiB |
BIN
public/images/login/push-300.png
Normal file
BIN
public/images/login/push-300.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 100 KiB |
|
@ -394,7 +394,7 @@ body {
|
||||||
color: blue;
|
color: blue;
|
||||||
}
|
}
|
||||||
|
|
||||||
#loginpanel, #createpanel, #resetpanel, #tokenpanel, #resettokenpanel, #resetpasswordpanel, #resetpasswordpanel, #checkemailpanel {
|
#loginpanel, #createpanel, #resetpanel, #tokenpanel, #resettokenpanel, #resetpasswordpanel, #resetpasswordpanel, #checkemailpanel, #waitpushpanel {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
background-color: #979797;
|
background-color: #979797;
|
||||||
|
|
|
@ -2032,6 +2032,7 @@
|
||||||
QV('authKeySetupCheck', userinfo.otphkeys > 0);
|
QV('authKeySetupCheck', userinfo.otphkeys > 0);
|
||||||
QV('authPushAuthDevCheck', (userinfo.otpdev > 0) && ((features2 & 2) != 0));
|
QV('authPushAuthDevCheck', (userinfo.otpdev > 0) && ((features2 & 2) != 0));
|
||||||
QV('authCodesSetupCheck', userinfo.otpkeys > 0);
|
QV('authCodesSetupCheck', userinfo.otpkeys > 0);
|
||||||
|
QV('managePushAuthDev', (features2 & 2) && (count2factoraAuths() > 0));
|
||||||
mainUpdate(4 + 128 + 4096);
|
mainUpdate(4 + 128 + 4096);
|
||||||
|
|
||||||
// Check if none or at least 2 factors are enabled.
|
// Check if none or at least 2 factors are enabled.
|
||||||
|
|
|
@ -186,6 +186,7 @@
|
||||||
<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=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=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=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=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>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -219,6 +220,7 @@
|
||||||
<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=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=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=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=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>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -281,6 +283,22 @@
|
||||||
<input id=checkemailformargs name="urlargs" type="hidden" value="" />
|
<input id=checkemailformargs name="urlargs" type="hidden" value="" />
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
<div id=waitpushpanel style="display:none">
|
||||||
|
<div id=message8></div>
|
||||||
|
<table style="width:100%">
|
||||||
|
<tr>
|
||||||
|
<td style="align-content:center;padding-top:10px">
|
||||||
|
<img src="images/login/push-150.png" srcset="images/login/push-300.png 2x" loading="lazy" width="265" height="150" />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="align-content:center;padding-top:10px">
|
||||||
|
<label id=tokenInputRememberLabel2><input id=tokenInputRemember2 name=remembertoken type=checkbox /><span id=tokenInputRememberSpan2></span></label>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<hr /><a onclick="return xgo(1,event);" href="#" style=cursor:pointer>Back to login</a>
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr id="welcomeTextRow"><td><div id="welcomeText" style="color:white;text-align:center;margin-left:20px;margin-right:20px"></div></td></tr>
|
<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 @@
|
||||||
var publicKeyCredentialRequestOptions = null;
|
var publicKeyCredentialRequestOptions = null;
|
||||||
var otpemail = (decodeURIComponent('{{{otpemail}}}') === 'true');
|
var otpemail = (decodeURIComponent('{{{otpemail}}}') === 'true');
|
||||||
var otpsms = (decodeURIComponent('{{{otpsms}}}') === 'true');
|
var otpsms = (decodeURIComponent('{{{otpsms}}}') === 'true');
|
||||||
|
var otppush = (decodeURIComponent('{{{otppush}}}') === 'true');
|
||||||
var twoFactorCookieDays = parseInt('{{{twoFactorCookieDays}}}');
|
var twoFactorCookieDays = parseInt('{{{twoFactorCookieDays}}}');
|
||||||
var authStrategies = '{{{authStrategies}}}'.split(',');
|
var authStrategies = '{{{authStrategies}}}'.split(',');
|
||||||
|
|
||||||
|
@ -342,15 +361,16 @@
|
||||||
// Display the right server message
|
// Display the right server message
|
||||||
var i;
|
var i;
|
||||||
var messageid = parseInt('{{{messageid}}}');
|
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.", "Notification sent, {0}."];
|
||||||
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."];
|
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."];
|
||||||
if (messageid > 0) {
|
if (messageid > 0) {
|
||||||
var msg = '';
|
var msg = '';
|
||||||
if ((messageid < 100) && (messageid < okmessages.length)) { msg = okmessages[messageid]; }
|
if ((messageid < 100) && (messageid < okmessages.length)) { msg = okmessages[messageid]; }
|
||||||
else if ((messageid >= 100) && ((messageid - 100) < failmessages.length)) { msg = failmessages[messageid - 100]; }
|
else if ((messageid >= 100) && ((messageid - 100) < failmessages.length)) { msg = failmessages[messageid - 100]; }
|
||||||
|
if (messageid == 5) { msg = format(msg, passhint); }
|
||||||
if (msg != '') {
|
if (msg != '') {
|
||||||
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 />'); }
|
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 />'); }
|
||||||
for (i = 1; i < 8; i++) { QH('message' + i, msg); }
|
for (i = 1; i < 9; i++) { QH('message' + i, msg); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -369,8 +389,11 @@
|
||||||
if (twoFactorCookieDays > 0) {
|
if (twoFactorCookieDays > 0) {
|
||||||
QV('tokenInputRememberLabel', true);
|
QV('tokenInputRememberLabel', true);
|
||||||
QH('tokenInputRememberSpan', format("Remember this device for {0} days.", twoFactorCookieDays));
|
QH('tokenInputRememberSpan', format("Remember this device for {0} days.", twoFactorCookieDays));
|
||||||
|
QV('tokenInputRememberLabel2', true);
|
||||||
|
QH('tokenInputRememberSpan2', format("Remember this device for {0} days.", twoFactorCookieDays));
|
||||||
} else {
|
} else {
|
||||||
QV('tokenInputRememberLabel', false);
|
QV('tokenInputRememberLabel', false);
|
||||||
|
QV('tokenInputRememberLabel2', false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If URL arguments are provided, add them to form posts
|
// If URL arguments are provided, add them to form posts
|
||||||
|
@ -443,10 +466,12 @@
|
||||||
var twofakey = (hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn');
|
var twofakey = (hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn');
|
||||||
var emailkey = otpemail && (messageid != 2) && (messageid != 4);
|
var emailkey = otpemail && (messageid != 2) && (messageid != 4);
|
||||||
var smskey = otpsms && (messageid != 2) && (messageid != 4);
|
var smskey = otpsms && (messageid != 2) && (messageid != 4);
|
||||||
|
var pushkey = otppush && (messageid != 2) && (messageid != 4);
|
||||||
QV('securityKeyButton', twofakey);
|
QV('securityKeyButton', twofakey);
|
||||||
QV('emailKeyButton', emailkey);
|
QV('emailKeyButton', emailkey);
|
||||||
QV('smsKeyButton', smskey);
|
QV('smsKeyButton', smskey);
|
||||||
QV('2farow', twofakey || emailkey || smskey);
|
QV('pushKeyButton', pushkey);
|
||||||
|
QV('2farow', twofakey || emailkey || smskey || pushkey);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loginMode == '5') {
|
if (loginMode == '5') {
|
||||||
|
@ -454,10 +479,12 @@
|
||||||
var twofakey = (hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn');
|
var twofakey = (hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn');
|
||||||
var emailkey = otpemail && (messageid != 2) && (messageid != 4);
|
var emailkey = otpemail && (messageid != 2) && (messageid != 4);
|
||||||
var smskey = otpsms && (messageid != 2) && (messageid != 4);
|
var smskey = otpsms && (messageid != 2) && (messageid != 4);
|
||||||
|
var pushkey = otppush && (messageid != 2) && (messageid != 4);
|
||||||
QV('securityKeyButton2', twofakey);
|
QV('securityKeyButton2', twofakey);
|
||||||
QV('emailKeyButton2', emailkey);
|
QV('emailKeyButton2', emailkey);
|
||||||
QV('smsKeyButton2', smskey);
|
QV('smsKeyButton2', smskey);
|
||||||
QV('2farow2', twofakey || emailkey || smskey);
|
QV('pushKeyButton', pushkey);
|
||||||
|
QV('2farow2', twofakey || emailkey || smskey || pushkey);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -565,6 +592,18 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function usePushToken(panelAction) {
|
||||||
|
if (panelAction == 1) {
|
||||||
|
Q('hwtokenInput').value = '**push**';
|
||||||
|
QE('tokenOkButton', true);
|
||||||
|
Q('tokenOkButton').click();
|
||||||
|
} else if (panelAction == 2) {
|
||||||
|
Q('resetHwtokenInput').value = '**push**';
|
||||||
|
QE('resetTokenOkButton', true);
|
||||||
|
Q('resetTokenOkButton').click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function showPassHint(e) {
|
function showPassHint(e) {
|
||||||
messagebox("Password Hint", passhint);
|
messagebox("Password Hint", passhint);
|
||||||
haltEvent(e);
|
haltEvent(e);
|
||||||
|
@ -595,6 +634,7 @@
|
||||||
QV('resettokenpanel', x == 5);
|
QV('resettokenpanel', x == 5);
|
||||||
QV('resetpasswordpanel', x == 6);
|
QV('resetpasswordpanel', x == 6);
|
||||||
QV('checkemailpanel', x == 7);
|
QV('checkemailpanel', x == 7);
|
||||||
|
QV('waitpushpanel', x == 8);
|
||||||
if (x == 1) { Q('username').focus(); }
|
if (x == 1) { Q('username').focus(); }
|
||||||
if (x == 2) { if (features & 0x200000) { Q('aemail').focus(); } else { Q('ausername').focus(); } } // Email is username
|
if (x == 2) { if (features & 0x200000) { Q('aemail').focus(); } else { Q('ausername').focus(); } } // Email is username
|
||||||
if (x == 3) { Q('remail').focus(); }
|
if (x == 3) { Q('remail').focus(); }
|
||||||
|
|
61
webserver.js
61
webserver.js
|
@ -924,6 +924,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||||
|
|
||||||
var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (domain.mailserver != null) && (user.email != null) && (user.emailVerified == true) && (user.otpekey != null));
|
var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (domain.mailserver != null) && (user.email != null) && (user.emailVerified == true) && (user.otpekey != null));
|
||||||
var sms2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)) && (parent.smsserver != null) && (user.phone != null));
|
var sms2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)) && (parent.smsserver != null) && (user.phone != null));
|
||||||
|
var push2fa = ((parent.firebase != null) && (user.otpdev != null));
|
||||||
|
|
||||||
// Check if this user has 2-step login active
|
// Check if this user has 2-step login active
|
||||||
if ((req.session.loginmode != '6') && checkUserOneTimePasswordRequired(domain, user, req)) {
|
if ((req.session.loginmode != '6') && checkUserOneTimePasswordRequired(domain, user, req)) {
|
||||||
|
@ -951,6 +952,29 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((req.body.hwtoken == '**push**') && push2fa) {
|
||||||
|
// Cause push notification to device
|
||||||
|
const logincode = obj.common.zeroPad(getRandomSixDigitInteger(), 6);
|
||||||
|
const code = Buffer.from(logincode).toString('base64');
|
||||||
|
const authCookie = parent.encodeCookie({ a: 'checkAuth', c: code, u: user._id, n: user.otpdev });
|
||||||
|
var payload = { notification: { title: "MeshCentral", body: user.name + " authentication" }, data: { url: '2fa://auth?code=' + code + '&c=' + authCookie } };
|
||||||
|
var options = { priority: 'High', timeToLive: 60 }; // TTL: 1 minute
|
||||||
|
parent.firebase.sendToDevice(user.otpdev, payload, options, function (id, err, errdesc) {
|
||||||
|
if (err == null) {
|
||||||
|
// Request that the login page wait for device auth
|
||||||
|
req.session.messageid = 5; // "Notification sent." message
|
||||||
|
req.session.passhint = logincode;
|
||||||
|
req.session.loginmode = '8';
|
||||||
|
} else {
|
||||||
|
// Indicate the push notification failed
|
||||||
|
req.session.messageid = 116; // "Unable to send device notification." message
|
||||||
|
req.session.loginmode = '4';
|
||||||
|
}
|
||||||
|
if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); }
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
checkUserOneTimePassword(req, domain, user, req.body.token, req.body.hwtoken, function (result) {
|
checkUserOneTimePassword(req, domain, user, req.body.token, req.body.hwtoken, function (result) {
|
||||||
if (result == false) {
|
if (result == false) {
|
||||||
var randomWaitTime = 0;
|
var randomWaitTime = 0;
|
||||||
|
@ -973,6 +997,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||||
req.session.loginmode = '4';
|
req.session.loginmode = '4';
|
||||||
req.session.tokenemail = ((user.email != null) && (user.emailVerified == true) && (domain.mailserver != null) && (user.otpekey != null));
|
req.session.tokenemail = ((user.email != null) && (user.emailVerified == true) && (domain.mailserver != null) && (user.otpekey != null));
|
||||||
req.session.tokensms = ((user.phone != null) && (parent.smsserver != null));
|
req.session.tokensms = ((user.phone != null) && (parent.smsserver != null));
|
||||||
|
req.session.tokenpush = ((user.otpdev != null) && (parent.firebase != null));
|
||||||
req.session.tokenuserid = userid;
|
req.session.tokenuserid = userid;
|
||||||
req.session.tokenusername = xusername;
|
req.session.tokenusername = xusername;
|
||||||
req.session.tokenpassword = xpassword;
|
req.session.tokenpassword = xpassword;
|
||||||
|
@ -1097,6 +1122,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||||
delete req.session.tokenpassword;
|
delete req.session.tokenpassword;
|
||||||
delete req.session.tokenemail;
|
delete req.session.tokenemail;
|
||||||
delete req.session.tokensms;
|
delete req.session.tokensms;
|
||||||
|
delete req.session.tokenpush;
|
||||||
delete req.session.messageid;
|
delete req.session.messageid;
|
||||||
delete req.session.passhint;
|
delete req.session.passhint;
|
||||||
delete req.session.cuserid;
|
delete req.session.cuserid;
|
||||||
|
@ -1301,6 +1327,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||||
delete req.session.resettokenpassword;
|
delete req.session.resettokenpassword;
|
||||||
delete req.session.tokenemail;
|
delete req.session.tokenemail;
|
||||||
delete req.session.tokensms;
|
delete req.session.tokensms;
|
||||||
|
delete req.session.tokenpush;
|
||||||
delete req.session.messageid;
|
delete req.session.messageid;
|
||||||
delete req.session.passhint;
|
delete req.session.passhint;
|
||||||
delete req.session.cuserid;
|
delete req.session.cuserid;
|
||||||
|
@ -1382,6 +1409,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||||
delete req.session.resettokenpassword;
|
delete req.session.resettokenpassword;
|
||||||
delete req.session.tokenemail;
|
delete req.session.tokenemail;
|
||||||
delete req.session.tokensms;
|
delete req.session.tokensms;
|
||||||
|
delete req.session.tokenpush;
|
||||||
delete req.session.messageid;
|
delete req.session.messageid;
|
||||||
delete req.session.passhint;
|
delete req.session.passhint;
|
||||||
delete req.session.cuserid;
|
delete req.session.cuserid;
|
||||||
|
@ -2638,7 +2666,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||||
var passhint = null, msgid = 0;
|
var passhint = null, msgid = 0;
|
||||||
if (req.session != null) {
|
if (req.session != null) {
|
||||||
msgid = req.session.messageid;
|
msgid = req.session.messageid;
|
||||||
if ((loginmode == '7') || ((domain.passwordrequirements != null) && (domain.passwordrequirements.hint === true))) { passhint = EscapeHtml(req.session.passhint); }
|
if ((msgid == 5) || (loginmode == '7') || ((domain.passwordrequirements != null) && (domain.passwordrequirements.hint === true))) { passhint = EscapeHtml(req.session.passhint); }
|
||||||
delete req.session.messageid;
|
delete req.session.messageid;
|
||||||
delete req.session.passhint;
|
delete req.session.passhint;
|
||||||
}
|
}
|
||||||
|
@ -2658,6 +2686,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||||
if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.email2factor == false)) { otpemail = false; }
|
if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.email2factor == false)) { otpemail = false; }
|
||||||
var otpsms = (parent.smsserver != null) && (req.session != null) && (req.session.tokensms == true);
|
var otpsms = (parent.smsserver != null) && (req.session != null) && (req.session.tokensms == true);
|
||||||
if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.sms2factor == false)) { otpsms = false; }
|
if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.sms2factor == false)) { otpsms = false; }
|
||||||
|
var otppush = (parent.firebase != null) && (req.session != null) && (req.session.tokenpush == true);
|
||||||
|
//if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.push2factor == false)) { otppush = false; }
|
||||||
|
|
||||||
// See if we support two-factor trusted cookies
|
// See if we support two-factor trusted cookies
|
||||||
var twoFactorCookieDays = 30;
|
var twoFactorCookieDays = 30;
|
||||||
|
@ -2704,6 +2734,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||||
hwstate: hwstate,
|
hwstate: hwstate,
|
||||||
otpemail: otpemail,
|
otpemail: otpemail,
|
||||||
otpsms: otpsms,
|
otpsms: otpsms,
|
||||||
|
otppush: otppush,
|
||||||
twoFactorCookieDays: twoFactorCookieDays,
|
twoFactorCookieDays: twoFactorCookieDays,
|
||||||
authStrategies: authStrategies.join(','),
|
authStrategies: authStrategies.join(','),
|
||||||
loginpicture: (typeof domain.loginpicture == 'string')
|
loginpicture: (typeof domain.loginpicture == 'string')
|
||||||
|
@ -5844,7 +5875,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||||
// Figure out if email 2FA is allowed
|
// Figure out if email 2FA is allowed
|
||||||
var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (domain.mailserver != null) && (user.otpekey != null));
|
var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (domain.mailserver != null) && (user.otpekey != null));
|
||||||
var sms2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)) && (parent.smsserver != null) && (user.phone != null));
|
var sms2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)) && (parent.smsserver != null) && (user.phone != null));
|
||||||
if ((typeof command.token != 'string') || (command.token == '**email**') || (command.token == '**sms**')) {
|
//var push2fa = ((parent.firebase != null) && (user.otpdev != null));
|
||||||
|
if ((typeof command.token != 'string') || (command.token == '**email**') || (command.token == '**sms**')/* || (command.token == '**push**')*/) {
|
||||||
if ((command.token == '**email**') && (email2fa == true)) {
|
if ((command.token == '**email**') && (email2fa == true)) {
|
||||||
// Cause a token to be sent to the user's registered email
|
// Cause a token to be sent to the user's registered email
|
||||||
user.otpekey = { k: obj.common.zeroPad(getRandomEightDigitInteger(), 8), d: Date.now() };
|
user.otpekey = { k: obj.common.zeroPad(getRandomEightDigitInteger(), 8), d: Date.now() };
|
||||||
|
@ -5861,6 +5893,17 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||||
parent.smsserver.sendToken(domain, user.phone, user.otpsms.k, obj.getLanguageCodes(req));
|
parent.smsserver.sendToken(domain, user.phone, user.otpsms.k, obj.getLanguageCodes(req));
|
||||||
// Ask for a login token & confirm sms was sent
|
// Ask for a login token & confirm sms was sent
|
||||||
try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired', email2fa: email2fa, sms2fa: sms2fa, sms2fasent: true, twoFactorCookieDays: twoFactorCookieDays })); ws.close(); } catch (e) { }
|
try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired', email2fa: email2fa, sms2fa: sms2fa, sms2fasent: true, twoFactorCookieDays: twoFactorCookieDays })); ws.close(); } catch (e) { }
|
||||||
|
/*
|
||||||
|
} else if ((command.token == '**push**') && (push2fa == true)) {
|
||||||
|
// Cause push notification to device
|
||||||
|
const code = Buffer.from(obj.common.zeroPad(getRandomSixDigitInteger(), 6)).toString('base64');
|
||||||
|
const authCookie = parent.encodeCookie({ a: 'checkAuth', c: code, u: user._id, n: user.otpdev });
|
||||||
|
var payload = { notification: { title: "MeshCentral", body: user.name + " authentication" }, data: { url: '2fa://auth?code=' + code + '&c=' + authCookie } };
|
||||||
|
var options = { priority: 'High', timeToLive: 60 }; // TTL: 1 minute
|
||||||
|
parent.firebase.sendToDevice(user.otpdev, payload, options, function (id, err, errdesc) {
|
||||||
|
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); }
|
||||||
|
});
|
||||||
|
*/
|
||||||
} else {
|
} else {
|
||||||
// Ask for a login token
|
// Ask for a login token
|
||||||
parent.debug('web', 'Asking for login token');
|
parent.debug('web', 'Asking for login token');
|
||||||
|
@ -5965,7 +6008,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||||
// Figure out if email 2FA is allowed
|
// Figure out if email 2FA is allowed
|
||||||
var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (domain.mailserver != null) && (user.otpekey != null));
|
var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (domain.mailserver != null) && (user.otpekey != null));
|
||||||
var sms2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)) && (parent.smsserver != null) && (user.phone != null));
|
var sms2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)) && (parent.smsserver != null) && (user.phone != null));
|
||||||
if ((typeof req.query.token != 'string') || (req.query.token == '**email**') || (req.query.token == '**sms**')) {
|
//var push2fa = ((parent.firebase != null) && (user.otpdev != null));
|
||||||
|
if ((typeof req.query.token != 'string') || (req.query.token == '**email**') || (req.query.token == '**sms**')/* || (req.query.token == '**push**')*/) {
|
||||||
if ((req.query.token == '**email**') && (email2fa == true)) {
|
if ((req.query.token == '**email**') && (email2fa == true)) {
|
||||||
// Cause a token to be sent to the user's registered email
|
// Cause a token to be sent to the user's registered email
|
||||||
user.otpekey = { k: obj.common.zeroPad(getRandomEightDigitInteger(), 8), d: Date.now() };
|
user.otpekey = { k: obj.common.zeroPad(getRandomEightDigitInteger(), 8), d: Date.now() };
|
||||||
|
@ -5982,6 +6026,17 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||||
parent.smsserver.sendToken(domain, user.phone, user.otpsms.k, obj.getLanguageCodes(req));
|
parent.smsserver.sendToken(domain, user.phone, user.otpsms.k, obj.getLanguageCodes(req));
|
||||||
// Ask for a login token & confirm sms was sent
|
// Ask for a login token & confirm sms was sent
|
||||||
try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired', email2fa: email2fa, sms2fa: sms2fa, sms2fasent: true, twoFactorCookieDays: twoFactorCookieDays })); ws.close(); } catch (e) { }
|
try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired', email2fa: email2fa, sms2fa: sms2fa, sms2fasent: true, twoFactorCookieDays: twoFactorCookieDays })); ws.close(); } catch (e) { }
|
||||||
|
/*
|
||||||
|
} else if ((command.token == '**push**') && (push2fa == true)) {
|
||||||
|
// Cause push notification to device
|
||||||
|
const code = Buffer.from(obj.common.zeroPad(getRandomSixDigitInteger(), 6)).toString('base64');
|
||||||
|
const authCookie = parent.encodeCookie({ a: 'checkAuth', c: code, u: user._id, n: user.otpdev });
|
||||||
|
var payload = { notification: { title: "MeshCentral", body: user.name + " authentication" }, data: { url: '2fa://auth?code=' + code + '&c=' + authCookie } };
|
||||||
|
var options = { priority: 'High', timeToLive: 60 }; // TTL: 1 minute
|
||||||
|
parent.firebase.sendToDevice(user.otpdev, payload, options, function (id, err, errdesc) {
|
||||||
|
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); }
|
||||||
|
});
|
||||||
|
*/
|
||||||
} else {
|
} else {
|
||||||
// Ask for a login token
|
// Ask for a login token
|
||||||
parent.debug('web', 'Asking for login token');
|
parent.debug('web', 'Asking for login token');
|
||||||
|
|
Loading…
Reference in a new issue