2019-10-21 18:59:20 -04:00
<!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">
<link rel="shortcut icon" type="image/x-icon" href=" {{{ domainurl }}} favicon.ico">
<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%">
<tbody><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 method="post">
<input type="hidden" name="action" value="login">
2019-11-17 17:33:29 -05:00
<div id="message1"></div>
2019-10-21 18:59:20 -04:00
<div>
<b>Log In</b>
</div>
<table>
<tbody><tr>
<td id="loginusername" align="right" width="100">Nom d'utilisateur:</td>
<td><input id="username" type="text" maxlength="64" name="username" onchange="validateLogin(1)" onkeyup="validateLogin(1,event)"></td>
</tr>
<tr>
2019-10-21 20:21:49 -04:00
<td align="right">Mot de passe:</td>
2019-10-21 18:59:20 -04:00
<td><input id="password" type="password" maxlength="256" name="password" autocomplete="off" onchange="validateLogin(2)" onkeyup="validateLogin(2,event)"></td>
</tr>
<tr>
2019-10-21 20:21:49 -04:00
<td><div id="showPassHintLink" style="display:none"><a onclick="showPassHint()" style="cursor:pointer">Dévoiler indice</a></div></td>
2019-10-21 18:59:20 -04:00
<td align="right"><input id="loginButton" type="submit" value="Log In" disabled="disabled"></td>
</tr>
</tbody></table>
<div id="hrAccountDiv" style="display:none"><hr></div>
<div id="resetAccountDiv" style="display:none;padding:2px">
2019-10-21 20:21:49 -04:00
<span id="resetAccountSpan">Forgot user/password?</span> <a onclick="xgo(3)" style="cursor:pointer">Réinitialiser le compte</a>.
2019-10-21 18:59:20 -04:00
</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>
<input id="loginformargs" name="urlargs" type="hidden" value="">
</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;position:relative">
<form method="post">
<input type="hidden" name="action" value="createaccount">
2019-11-17 17:33:29 -05:00
<div id="message2"></div>
2019-10-21 18:59:20 -04:00
<div>
<b>Account Creation</b>
</div>
<div id="passwordPolicyCallout" style="left:-5px;top:10px;width:100px;position:absolute;background-color:#FFC;border-radius:5px;padding:5px;box-shadow:0px 0px 15px #666;font-size:10px"></div>
<table>
<tbody><tr id="nuUserRow">
<td align="right" width="100">Nom d'utilisateur:</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>
2019-10-21 20:21:49 -04:00
<td align="right">Mot de passe:</td>
2019-10-21 18:59:20 -04:00
<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>
2019-10-21 20:21:49 -04:00
<td align="right">Mot de passe:</td>
2019-10-21 18:59:20 -04:00
<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 id="createPanelHint" style="display:none">
<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>
</tbody></table>
<hr><a onclick="xgo(1)" style="cursor:pointer">Back to login</a>
<input id="createformargs" name="urlargs" type="hidden" value="">
</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 method="post">
<input type="hidden" name="action" value="resetaccount">
2019-11-17 17:33:29 -05:00
<div id="message3"></div>
2019-10-21 18:59:20 -04:00
<div>
<b>Account Reset</b>
</div>
<table>
<tbody><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">
2019-10-21 20:21:49 -04:00
<div style="float:right"><input id="eresetButton" type="submit" value="Réinitialiser le Compte" disabled="disabled"></div>
2019-10-21 18:59:20 -04:00
<div id="passWarning" style="padding-top:6px"></div>
</td>
</tr>
</tbody></table>
<hr><a onclick="xgo(1)" style="cursor:pointer">Back to login</a>
<input id="resetformargs" name="urlargs" type="hidden" value="">
</form>
</div>
<div id="tokenpanel" style="background-color:#979797;border-radius:16px;width:260px;padding:16px;text-align:center;display:none;clear:both">
<form method="post" autocomplete="off">
<input type="hidden" name="action" value="tokenlogin">
<input type="hidden" name="hwstate" value=" {{{ hwstate }}} ">
2019-11-17 17:33:29 -05:00
<div id="message4"></div>
2019-10-21 18:59:20 -04:00
<table>
<tbody><tr>
<td align="right" width="100">Login token:</td>
<td>
<input id="tokenInput" type="text" name="token" maxlength="50" onchange="checkToken(event)" onkeyup="checkToken(event)" onkeydown="checkToken(event)" onfocus="checkTokenTimer(1)" onblur="checkTokenTimer(0)">
<input id="hwtokenInput" type="text" name="hwtoken" style="display:none">
</td>
</tr>
2019-11-29 01:29:22 -05:00
<tr>
<td colspan="2" style="align-content:center">
<label><input id="tokenInputRemember" name="remembertoken" type="checkbox">Remember this device for 30 days.</label>
</td>
</tr>
2019-10-21 18:59:20 -04:00
<tr>
<td colspan="2">
<div style="float:right"><input id="tokenOkButton" type="submit" value="Login" disabled="disabled"></div>
2019-11-29 01:29:22 -05:00
<div style="float:right"><input style="display:none;float:right" id="securityKeyButton" type="button" value="Use Security Key" onclick="useSecurityKey()"></div>
2019-10-21 18:59:20 -04:00
</td>
</tr>
</tbody></table>
<hr><a onclick="xgo(1)" style="cursor:pointer">Back to login</a>
<input id="tokenformargs" name="urlargs" type="hidden" value="">
</form>
</div>
<div id="resettokenpanel" style="background-color:#979797;border-radius:16px;width:260px;padding:16px;text-align:center;display:none;clear:both">
<form method="post" autocomplete="off">
<input type="hidden" name="action" value="resetaccount">
2019-11-17 17:33:29 -05:00
<div id="message5"></div>
2019-10-21 18:59:20 -04:00
<table>
<tbody><tr>
<td align="right" width="100">Login token:</td>
<td>
<input id="resetTokenInput" type="text" name="token" maxlength="50" onchange="resetCheckToken(event)" onpaste="resetCheckToken(event)" onkeyup="resetCheckToken(event)" onkeydown="resetCheckToken(event)">
<input id="resetHwtokenInput" type="text" name="hwtoken" style="display:none">
</td>
</tr>
<tr>
<td colspan="2">
<div style="float:right"><input id="resetTokenOkButton" type="submit" value="Login" disabled="disabled"></div>
</td>
</tr>
</tbody></table>
<hr><a onclick="xgo(1)" style="cursor:pointer">Back to login</a>
<input id="resettokenformargs" name="urlargs" type="hidden" value="">
</form>
</div>
<div id="resetpasswordpanel" style="position:relative;background-color:#979797;border-radius:16px;width:300px;padding:16px;text-align:center;display:none">
<form method="post">
<input type="hidden" name="action" value="resetpassword">
2019-11-17 17:33:29 -05:00
<div id="message6"></div>
2019-10-21 18:59:20 -04:00
<div id="rpasswordPolicyCallout" style="left:-10px;width:100px;display:none;position:absolute;background-color:#FFC;border-radius:5px;padding:5px;box-shadow:0px 0px 15px #666;font-size:10px"></div>
<table>
<tbody><tr>
2019-10-21 20:21:49 -04:00
<td id="rnuPass1" width="100" align="right">Mot de passe:</td>
2019-10-21 18:59:20 -04:00
<td><input id="rapassword1" type="password" name="rpassword1" autocomplete="off" maxlength="256" onkeydown="haltReturn(event)" onchange="validatePassReset(3,event)" onkeyup="validatePassReset(3,event)"></td>
</tr>
<tr>
2019-10-21 20:21:49 -04:00
<td id="rnuPass2" align="right">Mot de passe:</td>
2019-10-21 18:59:20 -04:00
<td><input id="rapassword2" type="password" name="rpassword2" autocomplete="off" maxlength="256" onkeydown="haltReturn(event)" onchange="validatePassReset(4,event)" onkeyup="validatePassReset(4,event)"></td>
</tr>
<tr id="resetpasswordpanelHint" style="display:none">
<td id="rnuHint" align="right">Password Hint:</td>
<td><input id="rapasswordhint" type="text" name="rpasswordhint" autocomplete="off" maxlength="256" onkeydown="haltReturn(event)" onchange="validatePassReset(5,event)" onkeyup="validatePassReset(5,event)"></td>
</tr>
<tr>
<td colspan="2">
2019-10-21 20:21:49 -04:00
<div style="float:right"><input id="resetPassButton" type="submit" value="Réinitialiser le mot de passe" disabled="disabled"></div>
2019-10-21 18:59:20 -04:00
<div id="rpassWarning" style="padding-top:6px"></div>
</td>
</tr>
</tbody></table>
<hr><a onclick="xgo(1)" style="cursor:pointer">Back to login</a>
<input id="resetpasswordformargs" name="urlargs" type="hidden" value="">
</form>
</div>
</td>
</tr>
</tbody></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%">
<tbody><tr>
<td style="text-align:left;color:white"> {{{ footer }}} </td>
<td style="text-align:right"> {{{ rootCertLink }}} <a href="terms">Terms & Privacy</a></td>
</tr>
</tbody></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="Annuler" 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';
2019-10-25 02:58:39 -04:00
var loginMode = ' {{{ log in mode }}} ';
var newAccount = ' {{{ newAccount }}} ';
2019-10-21 18:59:20 -04:00
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)); } else { passRequirements = { }; }
var passRequirementsEx = ((passRequirements.min != null) || (passRequirements.max != null) || (passRequirements.upper != null) || (passRequirements.lower != null) || (passRequirements.numeric != null) || (passRequirements.nonalpha != null));
var hardwareKeyChallenge = decodeURIComponent(' {{{ hkey }}} ');
2019-11-29 01:29:22 -05:00
var publicKeyCredentialRequestOptions = null;
2019-10-21 18:59:20 -04:00
var currentpanel = 0;
2019-11-17 17:33:29 -05:00
// Display the right server message
var messageid = parseInt(' {{{ messageid }}} ');
var okmessages = ['', "Hold on, reset mail sent."];
2019-11-18 20:31:42 -05:00
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."];
2019-11-17 17:33:29 -05:00
if (messageid > 0) {
var msg = '';
if ((messageid < 100) && (messageid < okmessages.length)) { msg = okmessages[messageid]; }
else if ((messageid >= 100) && ((messageid - 100) < failmessages.length)) { msg = failmessages[messageid - 100]; }
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 />'); }
for (var i = 1; i < 7; i++) { QH('message' + i, msg); }
}
}
2019-10-21 18:59:20 -04:00
// If URL arguments are provided, add them to form posts
if (window.location.href.indexOf('?') > 0) {
var urlargs = window.location.href.substring(window.location.href.indexOf('?'));
Q('loginformargs').value = urlargs;
Q('createformargs').value = urlargs;
Q('resetformargs').value = urlargs;
Q('tokenformargs').value = urlargs;
Q('resettokenformargs').value = urlargs;
Q('resetpasswordformargs').value = urlargs;
}
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; }
}
if (features & 0x200000) { // Email is username
QH('loginusername', "Email:");
QH('resetAccountSpan', "Forgot password?");
QV('nuUserRow', false);
}
QV('createPanelHint', passRequirements.hint === true);
QV('resetpasswordpanelHint', passRequirements.hint === true);
window.onresize = center;
center();
validateLogin();
validateCreate();
2019-10-25 02:58:39 -04:00
if (loginMode.length != 0) { go(parseInt(loginMode)); } else { go(1); }
QV('newAccountDiv', (newAccount === '1') || (newAccount === 'true')); // If new accounts are not allowed, don't display the new account link.
2019-10-21 18:59:20 -04:00
if ((passRequirements.hint === true) && (passhint != null) && (passhint.length > 0)) { QV('showPassHintLink', true); }
QV('newAccountPass', (newAccountPass == 1));
QV('resetAccountDiv', (emailCheck == true));
QV('hrAccountDiv', (emailCheck == true) || (newAccountPass == 1));
2019-10-25 02:58:39 -04:00
if (loginMode == '4') {
2019-10-21 18:59:20 -04:00
try { if (hardwareKeyChallenge.length > 0) { hardwareKeyChallenge = JSON.parse(hardwareKeyChallenge); } else { hardwareKeyChallenge = null; } } catch (ex) { hardwareKeyChallenge = null }
2019-11-29 01:29:22 -05:00
QV('securityKeyButton', (hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn'));
2019-10-21 18:59:20 -04:00
}
2019-10-25 02:58:39 -04:00
if (loginMode == '5') {
2019-10-21 18:59:20 -04:00
try { if (hardwareKeyChallenge.length > 0) { hardwareKeyChallenge = JSON.parse(hardwareKeyChallenge); } else { hardwareKeyChallenge = null; } } catch (ex) { hardwareKeyChallenge = null }
if ((hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn')) {
2019-11-29 01:29:22 -05:00
if (typeof hardwareKeyChallenge.challenge == 'string') { hardwareKeyChallenge.challenge = Uint8Array.from(atob(hardwareKeyChallenge.challenge), function (c) { return c.charCodeAt(0) }).buffer; }
2019-10-21 18:59:20 -04:00
2019-11-29 01:29:22 -05:00
publicKeyCredentialRequestOptions = { challenge: hardwareKeyChallenge.challenge, allowCredentials: [], timeout: hardwareKeyChallenge.timeout }
2019-10-21 18:59:20 -04:00
for (var i = 0; i < hardwareKeyChallenge.keyIds.length; i++) {
publicKeyCredentialRequestOptions.allowCredentials.push(
{ id: Uint8Array.from(atob(hardwareKeyChallenge.keyIds[i]), function (c) { return c.charCodeAt(0) }), type: 'public-key', transports: ['usb', 'ble', 'nfc'], }
);
}
// New WebAuthn hardware keys
navigator.credentials.get( { publicKey: publicKeyCredentialRequestOptions }).then(
function (rawAssertion) {
var assertion = {
id: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.rawId))),
clientDataJSON: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.clientDataJSON))),
userHandle: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.userHandle))),
signature: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.signature))),
authenticatorData: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.authenticatorData))),
};
Q('resetHwtokenInput').value = JSON.stringify(assertion);
QE('resetTokenOkButton', true);
Q('resetTokenOkButton').click();
},
function (error) { console.log('credentials-get error', error); }
);
}
}
}
2019-11-29 01:29:22 -05:00
// Use a hardware security key
function useSecurityKey() {
if ((hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn')) {
if (typeof hardwareKeyChallenge.challenge == 'string') { hardwareKeyChallenge.challenge = Uint8Array.from(atob(hardwareKeyChallenge.challenge), function (c) { return c.charCodeAt(0) }).buffer; }
publicKeyCredentialRequestOptions = { challenge: hardwareKeyChallenge.challenge, allowCredentials: [], timeout: hardwareKeyChallenge.timeout }
for (var i = 0; i < hardwareKeyChallenge.keyIds.length; i++) {
publicKeyCredentialRequestOptions.allowCredentials.push(
{ id: Uint8Array.from(atob(hardwareKeyChallenge.keyIds[i]), function (c) { return c.charCodeAt(0) }), type: 'public-key', transports: ['usb', 'ble', 'nfc'], }
);
}
// New WebAuthn hardware keys
navigator.credentials.get( { publicKey: publicKeyCredentialRequestOptions }).then(
function (rawAssertion) {
var assertion = {
id: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.rawId))),
clientDataJSON: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.clientDataJSON))),
userHandle: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.userHandle))),
signature: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.signature))),
authenticatorData: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.authenticatorData))),
};
Q('hwtokenInput').value = JSON.stringify(assertion);
QE('tokenOkButton', true);
Q('tokenOkButton').click();
},
function (error) { console.log('credentials-get error', error); }
);
}
}
2019-10-21 18:59:20 -04:00
function showPassHint() {
if (passRequirements.hint === true) { messagebox("Password Hint", passhint); }
}
function xgo(x) {
QV('message1', false);
QV('message2', false);
QV('message3', false);
QV('message4', false);
QV('message5', false);
QV('message6', false);
go(x);
}
function go(x) {
currentpanel = x;
setDialogMode(0);
QV('showPassHintLink', false);
QV('loginpanel', x == 1);
QV('createpanel', x == 2);
QV('resetpanel', x == 3);
QV('tokenpanel', x == 4);
QV('resettokenpanel', x == 5);
QV('resetpasswordpanel', x == 6);
if (x == 1) { Q('username').focus(); }
if (x == 2) { if (features & 0x200000) { Q('aemail').focus(); } else { Q('ausername').focus(); } } // Email is username
if (x == 3) { Q('remail').focus(); }
if (x == 4) { Q('tokenInput').focus(); }
if (x == 5) { Q('resetTokenInput').focus(); }
if (x == 6) { Q('rapassword1').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 = false;
if (features & 0x200000) { ok = true; } else { ok = (Q('ausername').value.length > 0) && (Q('ausername').value.indexOf(' ') == -1) && (Q('ausername').value.indexOf('"') == -1) && (Q('ausername').value.indexOf(',') == -1); }
ok &= ((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', '');
QV('passwordPolicyCallout', false);
} else {
if (!passRequirementsEx) {
// No password requirements, display password strength
var passStrength = checkPasswordStrength(Q('apassword1').value);
if (passStrength >= 80) { QH('passWarning', '<span style=color:green><b>' + "Mot de passe fort" + '</b><span>'); }
2019-10-21 20:21:49 -04:00
else if (passStrength >= 60) { QH('passWarning', '<span style=color:blue><b>' + "Bon mot de passe" + '</b><span>'); }
2019-10-21 18:59:20 -04:00
else { QH('passWarning', '<span style=color:red><b>' + "Mot de passe faible" + '</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
QV('passwordPolicyCallout', true);
QH('passwordPolicyCallout', passwordPolicyText(Q('apassword1').value));
} else {
QH('passWarning', '');
QV('passwordPolicyCallout', false);
}
}
}
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 validatePassReset(box, e) {
setDialogMode(0);
var pass1ok = (Q('rapassword1').value.length > 0);
var pass2ok = (Q('rapassword2').value.length > 0) && (Q('rapassword2').value == Q('rapassword1').value);
var ok = (pass1ok && pass2ok);
// Color the fields
QS('rnuPass1').color = pass1ok ? 'black' : '#7b241c';
QS('rnuPass2').color = pass2ok ? 'black' : '#7b241c';
if (Q('rapassword1').value == '') {
QH('rpassWarning', '');
QV('rpasswordPolicyCallout', false);
} else {
if (!passRequirementsEx) {
// No password requirements, display password strength
var passStrength = checkPasswordStrength(Q('rapassword1').value);
if (passStrength >= 80) { QH('rpassWarning', '<span style=color:green><b>' + "Mot de passe fort" + '</b><span>'); }
2019-10-21 20:21:49 -04:00
else if (passStrength >= 60) { QH('rpassWarning', '<span style=color:blue><b>' + "Bon mot de passe" + '</b><span>'); }
2019-10-21 18:59:20 -04:00
else { QH('rpassWarning', '<span style=color:red><b>' + "Mot de passe faible" + '</b><span>'); }
} else {
// Password requirements provided, use that
var passReq = checkPasswordRequirements(Q('rapassword1').value, passRequirements);
if (passReq == false) {
ok = false;
QS('rnuPass1').color = '#7b241c';
QS('rnuPass2').color = '#7b241c';
QH('rpassWarning', '<div style=color:red;cursor:pointer onclick=showPasswordPolicy()><b>' + "Password Policy" + '</b><div>'); // This is also a link to the password policy
QV('rpasswordPolicyCallout', true);
QH('rpasswordPolicyCallout', passwordPolicyText(Q('rapassword1').value));
} else {
QH('rpassWarning', '');
QV('rpasswordPolicyCallout', false);
}
}
}
if ((e != null) && (e.keyCode == 13)) {
if (box == 2) { Q('rapassword1').focus(); }
if (box == 3) { Q('rapassword2').focus(); }
if (box == 4) { Q('rapasswordhint').focus(); }
if (box == 6) { Q('resetPassButton').click(); }
}
if (e != null) { haltEvent(e); }
QE('resetPassButton', ok);
}
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); }
}
function passwordPolicyText(pass) {
var policy = '<div style=text-align:left>';
var counts = strCount(pass);
if (passRequirements.min && ((pass == null) || (pass.length < passRequirements.min))) { policy += format("Minimum length of { 0}", passRequirements.min) + '<br />'; }
if (passRequirements.max && ((pass == null) || (pass.length > passRequirements.max))) { policy += format("Maximum length of { 0}", passRequirements.max) + '<br />'; }
if (passRequirements.upper && ((pass == null) || (counts.upper < passRequirements.upper))) { policy += format(" { 0} upper case", passRequirements.upper) + '<br />'; }
if (passRequirements.lower && ((pass == null) || (counts.lower < passRequirements.lower))) { policy += format(" { 0} lower case", passRequirements.lower) + '<br />'; }
if (passRequirements.numeric && ((pass == null) || (counts.numeric < passRequirements.numeric))) { policy += format(" { 0} numeric", passRequirements.numeric) + '<br />'; }
if (passRequirements.nonalpha && ((pass == null) || (counts.nonalpha < passRequirements.nonalpha))) { policy += format(" { 0} non-alphanumeric", passRequirements.nonalpha) + '<br />'; }
policy += '</div>';
return policy;
}
// 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 counts = strCount(password);
if (requirements.numeric && (counts.numeric < requirements.numeric)) return false;
if (requirements.lower && (counts.lower < requirements.lower)) return false;
if (requirements.upper && (counts.upper < requirements.upper)) return false;
if (requirements.nonalpha && (counts.nonalpha < requirements.nonalpha)) return false;
return true;
}
function strCount(password) {
var counts = { numeric: 0, lower: 0, upper: 0, nonalpha: 0 };
if (typeof password != 'string') return counts;
for (var i = 0; i < password.length; i++) {
if (/\d/.test(password[i])) { counts.numeric++; }
if (/[a-z]/.test(password[i])) { counts.lower++; }
if (/[A-Z]/.test(password[i])) { counts.upper++; }
if (/\W/.test(password[i])) { counts.nonalpha++; }
}
return counts;
}
var xcheckTokenTimer = null;
function checkTokenTimer(enter) {
if ((enter == 0) && (xcheckTokenTimer != null)) { clearInterval(xcheckTokenTimer); xcheckTokenTimer = null; }
if ((enter == 1) && (xcheckTokenTimer == null)) { xcheckTokenTimer = setInterval(checkToken, 200); }
}
function checkToken() {
var t1 = Q('tokenInput').value, 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));
}
function resetCheckToken() {
var t1 = Q('resetTokenInput').value, t2 = t1.split(' ').join('');
if (t1 != t2) { Q('resetTokenInput').value = t2; }
QE('resetTokenOkButton', (Q('resetTokenInput').value.length == 6) || (Q('resetTokenInput').value.length == 8) || (Q('resetTokenInput').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 format(format) { var args = Array.prototype.slice.call(arguments, 1); return format.replace(/ { (\d+)}/g, function (match, number) { return typeof args[number] != 'undefined' ? args[number] : match; }); };
</script>
</body></html>