mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2025-03-09 15:40:18 +00:00
Completed support for hardware key 2-factor auth.
This commit is contained in:
parent
f57c1940ba
commit
70bc543699
9 changed files with 908 additions and 24 deletions
File diff suppressed because one or more lines are too long
|
@ -25,6 +25,7 @@
|
|||
<script type="text/javascript" src="scripts/agent-redir-rtc-0.1.0.js"></script>
|
||||
<script type="text/javascript" src="scripts/agent-desktop-0.0.2.js"></script>
|
||||
<script type="text/javascript" src="scripts/qrcode.min.js"></script>
|
||||
<script type="text/javascript" src="scripts/u2f-api.js"></script>
|
||||
<script keeplink=1 type="text/javascript" src="scripts/charts.js"></script>
|
||||
<script keeplink=1 type="text/javascript" src="scripts/filesaver.1.1.20151003.js"></script>
|
||||
<script keeplink=1 type="text/javascript" src="scripts/ol.js"></script>
|
||||
|
@ -251,8 +252,8 @@
|
|||
<span id="verifyEmailId" style="display:none"><a onclick="account_showVerifyEmail()" style="cursor:pointer">Verify email</a><br /></span>
|
||||
<span id="otpAuth" style="display:none"><a onclick="account_addOtp()" style="cursor:pointer">Add 2-step login</a><br /></span>
|
||||
<span id="otpAuthRemove" style="display:none"><a onclick="account_removeOtp()" style="cursor:pointer">Remove 2-step login</a><br /></span>
|
||||
<span id="manageOtp" style="display:none"><a onclick="account_manageOtp(0)" style="cursor:pointer">Manage one time passwords</a><br /></span>
|
||||
<span id="manageHardwareOtp" style="display:none"><a onclick="account_manageHardwareOtp(0)" style="cursor:pointer">Manage hardware login keys</a><br /></span>
|
||||
<span id="manageOtp" style="display:none"><a onclick="account_manageOtp(0)" style="cursor:pointer">Manage one time passwords</a><br /></span>
|
||||
<a onclick="account_showChangeEmail()" style="cursor:pointer">Change email address</a><br />
|
||||
<a onclick="account_showChangePassword()" style="cursor:pointer">Change password</a><br />
|
||||
<a onclick="account_showDeleteAccount()" style="cursor:pointer">Delete account</a><br />
|
||||
|
@ -1172,7 +1173,7 @@
|
|||
QV('verifyEmailId2', (userinfo.emailVerified !== true) && (userinfo.email != null) && (serverinfo.emailcheck == true));
|
||||
QV('otpAuth', ((features & 4096) != 0) && (userinfo.otpsecret != 1));
|
||||
QV('otpAuthRemove', ((features & 4096) != 0) && (userinfo.otpsecret == 1));
|
||||
QV('manageOtp', ((features & 4096) != 0) && (userinfo.otpsecret == 1));
|
||||
QV('manageOtp', ((features & 4096) != 0) && ((userinfo.otpsecret == 1) || (userinfo.otphkeys > 0)));
|
||||
QV('manageHardwareOtp', ((features & 0x5000) != 0)); // Requires 2-step login + YubiKey support
|
||||
}
|
||||
|
||||
|
@ -1457,13 +1458,15 @@
|
|||
x += "<br />";
|
||||
x += "<div><input type=button value='Close' onclick=setDialogMode(0) style=float:right></input>";
|
||||
//x += "<input type=button value='Add YubiKey' onclick='account_addYubiKey();'></input>";
|
||||
if (window.u2f) {
|
||||
x += "<input type=button value='Add Key' onclick='account_addhkey();'></input>";
|
||||
|
||||
if (u2fSupported()) {
|
||||
x += "<input id=d2addkey type=button value='Add Key' onclick='account_addhkey();'></input>";
|
||||
} else {
|
||||
x += "No hardware key support on this browser.";
|
||||
}
|
||||
x += "</div><br />";
|
||||
setDialogMode(2, "Manage Hardware Login Keys", 8, null, x, 'otpauth-hardware-manage');
|
||||
if (u2fSupported() && (message.keys.length > 0)) { QE('d2addkey', false); }
|
||||
break;
|
||||
}
|
||||
case 'otp-hkey-setup-request': {
|
||||
|
@ -1471,7 +1474,7 @@
|
|||
var x = "Press the key button now.<br /><br /><div style=width:100%;text-align:center><img src='images/hardware-keypress-120.png' /></div><input id=dp1keyname style=display:none value=" + message.name + " />";
|
||||
setDialogMode(2, "Add Hardware Login Key", 2, null, x);
|
||||
window.u2f.register(message.request.appId, [message.request], [], function (registrationResponse) {
|
||||
if (registrationResponse.errorCode == 0) {
|
||||
if (registrationResponse.registrationData) {
|
||||
meshserver.send({ action: 'otp-hkey-setup-response', request: message.request, response: registrationResponse, name: Q('dp1keyname').value });
|
||||
setDialogMode(2, "Add Hardware Login Key", 0, null, '<br />Checking...<br /><br /><br />', 'otpauth-hardware-manage');
|
||||
} else {
|
||||
|
@ -5297,8 +5300,8 @@
|
|||
|
||||
function account_manageOtp(action) {
|
||||
if ((xxdialogMode == 2) && (xxdialogTag == 'otpauth-manage')) { dialogclose(0); }
|
||||
if (xxdialogMode || (userinfo.otpsecret != 1) || ((features & 4096) == 0)) return;
|
||||
meshserver.send({ action: 'otpauth-getpasswords', subaction: action });
|
||||
if (xxdialogMode || ((features & 4096) == 0)) return;
|
||||
if ((userinfo.otpsecret == 1) || (userinfo.otphkeys > 0)) { meshserver.send({ action: 'otpauth-getpasswords', subaction: action }); }
|
||||
}
|
||||
|
||||
function account_manageHardwareOtp() {
|
||||
|
@ -5309,17 +5312,19 @@
|
|||
|
||||
function account_addhkey() {
|
||||
var x = "Type in the name of the key to add.<br /><br />";
|
||||
x += addHtmlValue('Key Name', '<input id=dp1keyname style=width:230px maxlength=20 autocomplete=off onchange=account_addhkeyValidate() onkeyup=account_addhkeyValidate() />');
|
||||
x += addHtmlValue('Key Name', '<input id=dp1keyname style=width:230px maxlength=20 autocomplete=off placeholder="MyKey" onkeyup=account_addhkeyValidate(event) />');
|
||||
setDialogMode(2, "Add Hardware Login Key", 3, account_addhkeyEx, x);
|
||||
account_addhkeyValidate();
|
||||
Q('dp1keyname').focus();
|
||||
}
|
||||
|
||||
function account_addhkeyValidate() {
|
||||
QE('idx_dlgOkButton', (Q('dp1keyname').value.length > 0));
|
||||
function account_addhkeyValidate(e) {
|
||||
if ((e != null) && (e.keyCode == 13)) { dialogclose(1); }
|
||||
}
|
||||
|
||||
function account_addhkeyEx() {
|
||||
meshserver.send({ action: 'otp-hkey-setup-request', name: Q('dp1keyname').value });
|
||||
var name = Q('dp1keyname').value;
|
||||
if (name == '') { name = 'MyKey'; }
|
||||
meshserver.send({ action: 'otp-hkey-setup-request', name: name });
|
||||
}
|
||||
|
||||
function account_addYubiKey() {
|
||||
|
@ -6943,6 +6948,8 @@
|
|||
function focusTextBox(x) { setTimeout(function(){ Q(x).selectionStart = Q(x).selectionEnd = 65535; Q(x).focus(); }, 0); }
|
||||
function validateEmail(v) { var emailReg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; return emailReg.test(v); } // New version
|
||||
function isPrivateIP(a) { return (a.startsWith('10.') || a.startsWith('172.16.') || a.startsWith('192.168.')); }
|
||||
function u2fSupported() { return (window.u2f && ((navigator.userAgent.indexOf('Chrome/') > 0) || (navigator.userAgent.indexOf('Firefox/') > 0) || (navigator.userAgent.indexOf('Opera/') > 0) || (navigator.userAgent.indexOf('Safari/') > 0))); }
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -7,6 +7,7 @@
|
|||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="format-detection" content="telephone=no" />
|
||||
<script type="text/javascript" src="scripts/common-0.0.1.js"></script>
|
||||
<script type="text/javascript" src="scripts/u2f-api.js"></script>
|
||||
<title>MeshCentral - Login</title>
|
||||
<style>
|
||||
a {
|
||||
|
@ -148,7 +149,11 @@
|
|||
<table>
|
||||
<tr>
|
||||
<td align=right width=100>Login token:</td>
|
||||
<td><input id=tokenInput type=text name=token maxlength=12 onkeypress="return (event.keyCode == 8) || (event.keyCode == 13) || (event.charCode >= 48 && event.charCode <= 57)" onkeyup=checkToken(event) onkeydown=checkToken(event) /></td>
|
||||
<td>
|
||||
<input id=tokenInput type=text name=token maxlength=12 onkeypress="return (event.keyCode == 8) || (event.keyCode == 13) || (event.charCode >= 48 && event.charCode <= 57)" onkeyup=checkToken(event) onkeydown=checkToken(event) />
|
||||
<input id=hwtokenInput1 type=text name=hwtoken1 style="display:none" />
|
||||
<input id=hwtokenInput2 type=text name=hwtoken2 style="display:none" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan=2>
|
||||
|
@ -200,6 +205,7 @@
|
|||
var features = parseInt('{{{features}}}');
|
||||
var passRequirements = "{{{passRequirements}}}";
|
||||
if (passRequirements != "") { passRequirements = JSON.parse(decodeURIComponent(passRequirements)); }
|
||||
var hardwareKeyChallenge = '{{{hkey}}}';
|
||||
|
||||
function startup() {
|
||||
if ((features & 32) == 0) {
|
||||
|
@ -219,6 +225,21 @@
|
|||
QV("newAccountPass", (newAccountPass == 1));
|
||||
QV("resetAccountDiv", (emailCheck == true));
|
||||
QV("hrAccountDiv", (emailCheck == true) || (newAccountPass == 1));
|
||||
|
||||
if ('{{loginmode}}' == '4') {
|
||||
try { if (hardwareKeyChallenge.length > 0) { hardwareKeyChallenge = JSON.parse(hardwareKeyChallenge); } else { hardwareKeyChallenge = null; } } catch (ex) { hardwareKeyChallenge = null }
|
||||
if ((hardwareKeyChallenge != null) && u2fSupported()) {
|
||||
var c = hardwareKeyChallenge[0];
|
||||
window.u2f.sign(c.appId, c.challenge, hardwareKeyChallenge, function (authResponse) {
|
||||
if (authResponse.signatureData) {
|
||||
Q('hwtokenInput1').value = JSON.stringify(hardwareKeyChallenge);
|
||||
Q('hwtokenInput2').value = JSON.stringify(authResponse);
|
||||
QE('tokenOkButton', true);
|
||||
Q('tokenOkButton').click();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function showPassHint() {
|
||||
|
@ -379,6 +400,7 @@
|
|||
function haltEvent(e) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
|
||||
function haltReturn(e) { if (e.keyCode == 13) { haltEvent(e); } }
|
||||
function validateEmail(v) { var emailReg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; return emailReg.test(v); } // New version
|
||||
function u2fSupported() { return (window.u2f && ((navigator.userAgent.indexOf('Chrome/') > 0) || (navigator.userAgent.indexOf('Firefox/') > 0) || (navigator.userAgent.indexOf('Opera/') > 0) || (navigator.userAgent.indexOf('Safari/') > 0))); }
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
@ -87,6 +87,7 @@
|
|||
}
|
||||
</style>
|
||||
<script type="text/javascript" src="scripts/common-0.0.1.js"></script>
|
||||
<script type="text/javascript" src="scripts/u2f-api.js"></script>
|
||||
<title>MeshCentral - Login</title>
|
||||
</head>
|
||||
<body onload="if (typeof(startup) !== 'undefined') startup();">
|
||||
|
@ -221,7 +222,11 @@
|
|||
<table>
|
||||
<tr>
|
||||
<td align=right width=100>Login token:</td>
|
||||
<td><input id=tokenInput type=text name=token maxlength=12 onkeypress="return (event.keyCode == 8) || (event.keyCode == 13) || (event.charCode >= 48 && event.charCode <= 57)" onkeyup=checkToken(event) onkeydown=checkToken(event) /></td>
|
||||
<td>
|
||||
<input id=tokenInput type=text name=token maxlength=12 onkeypress="return (event.keyCode == 8) || (event.keyCode == 13) || (event.charCode >= 48 && event.charCode <= 57)" onkeyup=checkToken(event) onkeydown=checkToken(event) />
|
||||
<input id=hwtokenInput1 type=text name=hwtoken1 style="display:none" />
|
||||
<input id=hwtokenInput2 type=text name=hwtoken2 style="display:none" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan=2>
|
||||
|
@ -277,6 +282,7 @@
|
|||
var newAccountPass = parseInt('{{{newAccountPass}}}');
|
||||
var emailCheck = ('{{{emailcheck}}}' == 'true');
|
||||
var passRequirements = "{{{passRequirements}}}";
|
||||
var hardwareKeyChallenge = '{{{hkey}}}';
|
||||
if (passRequirements != "") { passRequirements = JSON.parse(decodeURIComponent(passRequirements)); }
|
||||
var features = parseInt('{{{features}}}');
|
||||
var webPageFullScreen = getstore('webPageFullScreen', true);
|
||||
|
@ -302,6 +308,21 @@
|
|||
QV("newAccountPass", (newAccountPass == 1));
|
||||
QV("resetAccountDiv", (emailCheck == true));
|
||||
QV("hrAccountDiv", (emailCheck == true) || (newAccountPass == 1));
|
||||
|
||||
if ('{{loginmode}}' == '4') {
|
||||
try { if (hardwareKeyChallenge.length > 0) { hardwareKeyChallenge = JSON.parse(hardwareKeyChallenge); } else { hardwareKeyChallenge = null; } } catch (ex) { hardwareKeyChallenge = null }
|
||||
if ((hardwareKeyChallenge != null) && u2fSupported()) {
|
||||
var c = hardwareKeyChallenge[0];
|
||||
window.u2f.sign(c.appId, c.challenge, hardwareKeyChallenge, function (authResponse) {
|
||||
if (authResponse.signatureData) {
|
||||
Q('hwtokenInput1').value = JSON.stringify(hardwareKeyChallenge);
|
||||
Q('hwtokenInput2').value = JSON.stringify(authResponse);
|
||||
QE('tokenOkButton', true);
|
||||
Q('tokenOkButton').click();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function showPassHint() {
|
||||
|
@ -522,6 +543,7 @@
|
|||
function validateEmail(v) { var emailReg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; return emailReg.test(v); } // New version
|
||||
function putstore(name, val) { try { if (typeof (localStorage) === 'undefined') return; localStorage.setItem(name, val); } catch (e) { } }
|
||||
function getstore(name, val) { try { if (typeof (localStorage) === 'undefined') return val; var v = localStorage.getItem(name); if ((v == null) || (v == null)) return val; return v; } catch (e) { return val; } }
|
||||
function u2fSupported() { return (window.u2f && ((navigator.userAgent.indexOf('Chrome/') > 0) || (navigator.userAgent.indexOf('Firefox/') > 0) || (navigator.userAgent.indexOf('Opera/') > 0) || (navigator.userAgent.indexOf('Safari/') > 0))); }
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue