<!DOCTYPE html> <html dir="ltr" xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta content="text/html; charset=utf-8" http-equiv="Content-Type" /> <meta name="viewport" content="user-scalable=1.0,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0" /> <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 { color: #036; text-decoration: underline; } #footer a { color: #fff; text-decoration: underline; } #footer a:hover { color: #fff; text-decoration: none; } </style> </head> <body onload="if (typeof(startup) !== 'undefined') startup();" style="overflow-y:hidden;margin:0;padding:0;border:0;color:black;font-size:13px;font-family:\'Trebuchet MS\', Arial, Helvetica, sans-serif"> <div id=container> <div id=mastheadx></div> <div id=masthead style="background:url(logo.png) 0px 0px;background-size:341px 50px;background-color:#036;background-repeat:no-repeat;height:50px;width:100%;overflow:hidden"> <div style="float:left;height:66px;color:#c8c8c8;padding-left:10px;padding-top:6px"> <strong><font style="font-size:36px;font-family:Arial,Helvetica,sans-serif">{{{title}}}</font></strong> </div> <div style="float:left;height:66px;color:#c8c8c8;padding-left:5px;padding-top:10px"> <strong><font style="font-size:12px;font-family:Arial,Helvetica,sans-serif">{{{title2}}}</font></strong> </div> </div> <div id=page_content style="overflow-y:scroll;position:absolute;bottom:32px;top:50px;width:100%;display:flex;align-items:center"> <div id=column_l style="padding:10px;width:100%"> <table style="width:100%"> <tr> <td align=center> <div id=loginpanel style="background-color:#979797;border-radius:16px;width:260px;padding:16px;text-align:center;clear:both;display:none"> <form action="login" method=post> <div id=message1> {{{message}}} </div> <div> <b>Log In</b> </div> <table> <tr> <td align=right width=100>Username:</td> <td><input id=username type=text maxlength=64 name=username onchange=validateLogin(1) onkeyup=validateLogin(1,event) /></td> </tr> <tr> <td align=right>Password:</td> <td><input id=password type=password maxlength=256 name=password autocomplete=off onchange=validateLogin(2) onkeyup=validateLogin(2,event) /></td> </tr> <tr> <td><div id=showPassHintLink style=display:none><a onclick=showPassHint() style="cursor:pointer">Show Hint</a></div></td> <td align=right><input id=loginButton type=submit value="Log In" disabled="disabled" /></td> </tr> </table> <div id="hrAccountDiv" style="display:none"><hr /></div> <div id="resetAccountDiv" style="display:none;padding:2px"> Forgot user/password? <a onclick=xgo(3) style=cursor:pointer>Reset account</a>. </div> <div id="newAccountDiv" style="display:none;padding:2px"> Don't have an account? <a onclick=xgo(2) style=cursor:pointer>Create one</a>. </div> </form> </div> <div id=createpanel style="display:none"> <div style="background-color: #979797;border-radius:16px;width:260px;padding:16px;text-align:center;clear:both"> <form action=createaccount method=post> <div id=message2> {{{message}}} </div> <div> <b>Account Creation</b> </div> <table> <tr> <td align=right width=100>Username:</td> <td><input id=ausername type=text name=username onchange=validateCreate(1) maxlength=64 onkeydown=haltReturn(event) onkeyup=validateCreate(1,event) /></td> </tr> <tr> <td align=right width=100>Email:</td> <td><input id=aemail type=text name=email onchange=validateCreate(2) maxlength=256 onkeydown=haltReturn(event) onkeyup=validateCreate(2,event) /></td> </tr> <tr> <td align=right>Password:</td> <td><input id=apassword1 type=password name=password1 autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validateCreate(3) onkeyup=validateCreate(3,event) /></td> </tr> <tr> <td align=right>Password:</td> <td><input id=apassword2 type=password name=password2 autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validateCreate(4) onkeyup=validateCreate(4,event) /></td> </tr> <tr> <td align=right>Pass Hint:</td> <td><input id=apasswordhint type=text name=apasswordhint autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validateCreate(5) onkeyup=validateCreate(5,event) /></td> </tr> <tr id=newAccountPass title="Enter the account creation token"> <td align=right>Creation Token:</td> <td><input id=anewaccountpass type=password name=anewaccountpass autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validateCreate(6) onkeyup=validateCreate(6,event) /></td> </tr> <tr> <td colspan=2> <div style=float:right><input id=createButton type=submit value="Create Account" disabled="disabled" /></div> <div id=passWarning style="padding-top:6px"></div> </td> </tr> </table> <hr /><a onclick=xgo(1) style=cursor:pointer>Back to login</a> </form> </div> </div> <div id=resetpanel style="background-color:#979797;border-radius:16px;width:260px;padding:16px;text-align:center;display:none;clear:both"> <form action=resetaccount method=post> <div id=message3> {{{message}}} </div> <div> <b>Account Reset</b> </div> <table> <tr> <td align=right width=100>Email:</td> <td><input id=remail type=text name=email maxlength=256 onchange=validateReset() onkeyup=validateReset(event) /></td> </tr> <tr> <td colspan=2> <div style=float:right><input id=eresetButton type=submit value="Reset Account" disabled="disabled" /></div> <div id=passWarning style="padding-top:6px"></div> </td> </tr> </table> <hr /><a onclick=xgo(1) style=cursor:pointer>Back to login</a> </form> </div> <div id=tokenpanel style="background-color:#979797;border-radius:16px;width:260px;padding:16px;text-align:center;display:none;clear:both"> <form action=tokenlogin method=post autocomplete=off> <div id=message4> {{{message}}} </div> <table> <tr> <td align=right width=100>Login token:</td> <td> <input id=tokenInput type=text name=token maxlength=50 onkeyup=checkToken(event) onkeydown=checkToken(event) /> <input id=hwtokenInput type=text name=hwtoken style="display:none" /> </td> </tr> <tr> <td colspan=2> <div style=float:right><input id=tokenOkButton type=submit value="Login" disabled="disabled" /></div> </td> </tr> </table> <hr /><a onclick=xgo(1) style=cursor:pointer>Back to login</a> </form> </div> </td> </tr> </table> </div> </div> <div id=footer style="height:32px;width:100%;text-align:center;background-color:#113962;position:absolute;bottom:0px"> <table cellpadding=0 cellspacing=6 style=width:100%> <tr> <td style=text-align:left;color:white>{{{footer}}}</td> <td style=text-align:right>{{{rootCertLink}}} <a href=terms>Terms & Privacy</a></td> </tr> </table> </div> </div> <div id=dialog style="z-index:1000;background-color:#EEE;box-shadow:0px 0px 15px #666;font-family:Arial,Helvetica,sans-serif;border-radius:5px;position:fixed;top:180px;width:400px;display:none"> <div style="width:100%;background-color:#003366;color:#FFF;border-radius:5px 5px 0 0"> <div id=id_dialogclose style=float:right;padding:5px;cursor:pointer onclick=setDialogMode()><b>X</b></div> <div id=id_dialogtitle style=padding:5px></div> <div style=width:100%;margin:6px></div> </div> <div style="margin-right:16px;margin-left:8px"> <div id=dialog1 style="margin:auto;text-align:center;margin:3px"> <div id=id_dialogMessage style="padding:10px"></div> </div> <div id=dialog2 style="margin:auto;margin:3px"> <div id=id_dialogOptions></div> </div> </div> <div id="idx_dlgButtonBar" style="padding:10px;margin-bottom:20px"> <input id="idx_dlgCancelButton" type="button" value="Cancel" style="float:right;width:80px;margin-left:5px" onclick="dialogclose(0)"> <input id="idx_dlgOkButton" type="button" value="OK" style="float:right;width:80px" onclick="dialogclose(1)"> </div> </div> <script> 'use strict'; var passhint = "{{{passhint}}}"; var newAccountPass = parseInt('{{{newAccountPass}}}'); var emailCheck = ('{{{emailcheck}}}' == 'true'); var features = parseInt('{{{features}}}'); var passRequirements = "{{{passRequirements}}}"; if (passRequirements != "") { passRequirements = JSON.parse(decodeURIComponent(passRequirements)); } var hardwareKeyChallenge = '{{{hkey}}}'; function startup() { if ((features & 32) == 0) { // Guard against other site's top frames (web bugs). var loc = null; try { loc = top.location.toString().toLowerCase(); } catch (e) { } if (top != self && (loc == null || top.active == false)) { top.location = self.location; return; } } window.onresize = center; center(); validateLogin(); validateCreate(); if ('{{loginmode}}' != '') { go(parseInt('{{loginmode}}')); } else { go(1); } QV('newAccountDiv', ('{{{newAccount}}}' != '0') && ('{{{newAccount}}}' != 'false')); // If new accounts are not allowed, don't display the new account link. if ((passhint != null) && (passhint.length > 0)) { QV("showPassHintLink", true); } 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()) { window.u2f.sign(hardwareKeyChallenge.appId, hardwareKeyChallenge.challenge, hardwareKeyChallenge.registeredKeys, function (authResponse) { if (authResponse.signatureData) { Q('hwtokenInput').value = JSON.stringify(authResponse); QE('tokenOkButton', true); Q('tokenOkButton').click(); } }, hardwareKeyChallenge.timeoutSeconds); } } } function showPassHint() { messagebox("Password Hint", passhint); } function xgo(x) { QV('message1', false); QV('message2', false); go(x); } function go(x) { setDialogMode(0); QV("showPassHintLink", false); QV('loginpanel', x == 1); QV('createpanel', x == 2); QV('resetpanel', x == 3); QV('tokenpanel', x == 4); if (x == 1) { Q('username').focus(); } if (x == 2) { Q('ausername').focus(); } if (x == 3) { Q('remail').focus(); } if (x == 4) { Q('tokenInput').focus(); } } function validateLogin(box, e) { var ok = ((Q('username').value.length > 0) && (Q('username').value.indexOf(' ') == -1) && (Q('password').value.length > 0)); QE('loginButton', ok); setDialogMode(0); if ((e != null) && (e.keyCode == 13)) { if (box == 1) { Q('password').focus(); } else if (box == 2) { Q('loginButton').click(); } } if (e != null) { haltEvent(e); } } function validateCreate(box,e) { setDialogMode(0); var ok = ((Q('ausername').value.length > 0) && (Q('ausername').value.indexOf(' ') == -1) && (validateEmail(Q('aemail').value) == true) && (Q('apassword1').value.length > 0) && (Q('apassword2').value == Q('apassword1').value)); if ((newAccountPass == 1) && (Q('anewaccountpass').value.length == 0)) { ok = false; } if (Q('apassword1').value == '') { QH('passWarning', ''); } else { if (passRequirements == null || passRequirements == '') { // No password requirements, display password strength var passStrength = checkPasswordStrength(Q('apassword1').value); if (passStrength >= 80) { QH('passWarning', '<span style=color:green><b>Strong Password</b><span>'); } else if (passStrength >= 60) { QH('passWarning', '<span style=color:blue><b>Good Password</b><span>'); } else { QH('passWarning', '<span style=color:red><b>Weak Password</b><span>'); } } else { // Password requirements provided, use that var passReq = checkPasswordRequirements(Q('apassword1').value, passRequirements); if (passReq == false) { ok = false; //QS('nuPass1').color = '#7b241c'; //QS('nuPass2').color = '#7b241c'; QH('passWarning', '<span style=color:red><b>Password Policy</b><span>'); // TODO: Display problem hint } else { QH('passWarning', ''); } } } QE('createButton', ok); if ((e != null) && (e.keyCode == 13)) { if (box == 1) { Q('aemail').focus(); } if (box == 2) { Q('apassword1').focus(); } if (box == 3) { Q('apassword2').focus(); } if (box == 4) { Q('apasswordhint').focus(); } if (box == 5) { if (newAccountPass == 1) { Q('anewaccountpass').focus(); } else { Q('createButton').click(); } } if (box == 6) { Q('createButton').click(); } } if (e != null) { haltEvent(e); } } function validateReset(e) { setDialogMode(0); var x = validateEmail(Q('remail').value); QE('eresetButton', x); if ((e != null) && (e.keyCode == 13) && (x == true)) { Q('eresetButton').click(); } if (e != null) { haltEvent(e); } } // Return a password strength score function checkPasswordStrength(password) { var r = 0, letters = {}, varCount = 0, variations = { digits: /\d/.test(password), lower: /[a-z]/.test(password), upper: /[A-Z]/.test(password), nonWords: /\W/.test(password) } if (!password) return 0; for (var i = 0; i< password.length; i++) { letters[password[i]] = (letters[password[i]] || 0) + 1; r += 5.0 / letters[password[i]]; } for (var c in variations) { varCount += (variations[c] == true) ? 1 : 0; } return parseInt(r + (varCount - 1) * 10); } // Check password requirements function checkPasswordRequirements(password, requirements) { if ((requirements == null) || (requirements == '') || (typeof requirements != 'object')) return true; if (requirements.min) { if (password.length < requirements.min) return false; } if (requirements.max) { if (password.length > requirements.max) return false; } var num = 0, lower = 0, upper = 0, nonalpha = 0; for (var i = 0; i < password.length; i++) { if (/\d/.test(password[i])) { num++; } if (/[a-z]/.test(password[i])) { lower++; } if (/[A-Z]/.test(password[i])) { upper++; } if (/\W/.test(password[i])) { nonalpha++; } } if (requirements.num && (num < requirements.num)) return false; if (requirements.lower && (lower < requirements.lower)) return false; if (requirements.upper && (upper < requirements.upper)) return false; if (requirements.nonalpha && (nonalpha < requirements.nonalpha)) return false; return true; } function checkToken() { var t1 = Q('tokenInput').value; var t2 = t1.split(' ').join(''); if (t1 != t2) { Q('tokenInput').value = t2; } QE('tokenOkButton', (Q('tokenInput').value.length == 6) || (Q('tokenInput').value.length == 8) || (Q('tokenInput').value.length == 44)); } // // POPUP DIALOG // // undefined = Hidden, 1 = Generic Message var xxdialogMode; var xxdialogFunc; var xxdialogButtons; var xxdialogTag; var xxcurrentView = 0; // Display a dialog box // Parameters: Dialog Mode (0 = none), Dialog Title, Buttons (1 = OK, 2 = Cancel, 3 = OK & Cancel), Call back function(0 = Cancel, 1 = OK), Dialog Content (Mode 2 only) function setDialogMode(x, y, b, f, c, tag) { xxdialogMode = x; xxdialogFunc = f; xxdialogButtons = b; xxdialogTag = tag; QE('idx_dlgOkButton', true); QV('idx_dlgOkButton', b & 1); QV('idx_dlgCancelButton', b & 2); QV('id_dialogclose', (b & 2) || (b & 8)); QV('idx_dlgButtonBar', b & 7); if (y) QH('id_dialogtitle', y); for (var i = 1; i < 24; i++) { QV('dialog' + i, i == x); } // Edit this line when more dialogs are added QV('dialog', x); if (c) { if (x == 2) { QH('id_dialogOptions', c); } else { QH('id_dialogMessage', c); } } } function dialogclose(x) { var f = xxdialogFunc; var b = xxdialogButtons; var t = xxdialogTag; setDialogMode(); if (((b & 8) || x) && f) f(x, t); } function center() { QS('dialog').left = ((((getDocWidth() - 400) / 2)) + "px"); } function messagebox(t, m) { QH('id_dialogMessage', m); setDialogMode(1, t, 1); } function statusbox(t, m) { QH('id_dialogMessage', m); setDialogMode(1, t); } function getDocWidth() { if (window.innerWidth) return window.innerWidth; if (document.documentElement && document.documentElement.clientWidth && document.documentElement.clientWidth != 0) return document.documentElement.clientWidth; return document.getElementsByTagName('body')[0].clientWidth; } 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> </html>