mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2025-03-09 15:40:18 +00:00
Merge branch 'master' into moving-styles
This commit is contained in:
commit
47fc7a4452
32 changed files with 934 additions and 1501 deletions
File diff suppressed because one or more lines are too long
|
@ -25,7 +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/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>
|
||||
|
@ -141,6 +141,7 @@
|
|||
<table id=ServerSubMenu style=width:100%;height:22px cellpadding=0 cellspacing=0 class=style1>
|
||||
<tr>
|
||||
<td id=ServerGeneral style=width:100px;height:24px;cursor:pointer class=style3x onclick=go(6)>General</td>
|
||||
<td id=ServerStats style=width:100px;height:24px;cursor:pointer class=style3x onclick=go(40)>Stats</td>
|
||||
<td id=ServerConsole style=width:100px;height:24px;cursor:pointer class=style3x onclick=go(115)>Console</td>
|
||||
<td class=style3 style=height:24px> </td>
|
||||
</tr>
|
||||
|
@ -743,6 +744,30 @@
|
|||
</div>
|
||||
<div id=p31events style="max-height:calc(100vh - 267px);overflow-y:scroll"></div>
|
||||
</div>
|
||||
<div id=p40 style="display:none;height:calc(100vh - 170px)">
|
||||
<h1>My Server Stats</h1>
|
||||
<div style=width:100%;height:24px;background-color:#d3d9d6;margin-bottom:4px>
|
||||
<div style="float:right">
|
||||
<select id=p40type onchange=updateServerTimelineStats()>
|
||||
<option value=0>Connections</option>
|
||||
<option value=1>Memory</option>
|
||||
</select>
|
||||
<select id=p40time onchange=updateServerTimelineHours()>
|
||||
<option value=3>Last 3 hours</option>
|
||||
<option value=8>Last 8 hours</option>
|
||||
<option value=24>Last day</option>
|
||||
<option value=168>Last week</option>
|
||||
<option value=5040>Last 30 days</option>
|
||||
</select>
|
||||
<img src=images/link4.png height=10 width=10 title="Download data points (.csv)" style=cursor:pointer onclick=p40downloadEvents()>
|
||||
</div>
|
||||
<div>
|
||||
<input value="Refresh" type="button" onclick="refreshServerTimelineStats()" />
|
||||
<input id=p40log type="checkbox" onclick="updateServerTimelineHours()" />Log-X
|
||||
</div>
|
||||
</div>
|
||||
<canvas id=serverMainStats style="height:calc(100vh - 250px);max-height:calc(100vh - 250px);width:100%"></canvas>
|
||||
</div>
|
||||
<br id="column_l_bottomgap" />
|
||||
</div>
|
||||
<div id=footer class=noselect>
|
||||
|
@ -1014,8 +1039,9 @@
|
|||
for (var c = 1; c < 27; c++) x += "<option value='" + c + "'>Ctrl-" + String.fromCharCode(64 + c) + " (" + c + ")</option>";
|
||||
QH('specialkeylist', x);
|
||||
|
||||
// Setup server stats panel
|
||||
setupServerStats();
|
||||
// Setup server stats panels
|
||||
setupGeneralServerStats();
|
||||
setupServerTimelineStats();
|
||||
}
|
||||
|
||||
// Toggle the web page to full screen
|
||||
|
@ -1209,7 +1235,11 @@
|
|||
function onMessage(server, message) {
|
||||
switch (message.action) {
|
||||
case 'serverstats': {
|
||||
updateServerStats(message);
|
||||
updateGeneralServerStats(message);
|
||||
break;
|
||||
}
|
||||
case 'servertimelinestats': {
|
||||
setServerTimelineStats(message.events);
|
||||
break;
|
||||
}
|
||||
case 'authcookie': {
|
||||
|
@ -1519,8 +1549,10 @@
|
|||
meshserver.send({ action: 'otp-hkey-setup-response', response: registrationResponse, name: Q('dp1keyname').value });
|
||||
setDialogMode(2, "Add Security Key", 0, null, '<br />Checking...<br /><br /><br />', 'otpauth-hardware-manage');
|
||||
} else {
|
||||
var errorCodes = ['', 'Unknown error', 'Bad request', 'Unsupported configuration', 'This key was already registered', 'Timeout'];
|
||||
setDialogMode(2, "Add Security Key", 1, null, '<br />' + errorCodes[registrationResponse.errorCode] + '.<br /><br />');
|
||||
if (xxdialogMode && (xxdialogTag != 'otpauth-hardware-manage')) {
|
||||
var errorCodes = ['', 'Unknown error', 'Bad request', 'Unsupported configuration', 'This key was already registered', 'Timeout'];
|
||||
setDialogMode(2, "Add Security Key", 1, null, '<br />' + errorCodes[registrationResponse.errorCode] + '.<br /><br />');
|
||||
}
|
||||
}
|
||||
}, message.request.timeoutSeconds);
|
||||
break;
|
||||
|
@ -1540,15 +1572,15 @@
|
|||
setDialogMode(2, "Add Security Key", 2, null, x);
|
||||
|
||||
var publicKey = message.request;
|
||||
message.request.challenge = Uint8Array.from(atob(message.request.challenge), c => c.charCodeAt(0))
|
||||
message.request.user.id = Uint8Array.from(atob(message.request.user.id), c => c.charCodeAt(0))
|
||||
navigator.credentials.create({ publicKey })
|
||||
.then((newCredentialInfo) => {
|
||||
message.request.challenge = Uint8Array.from(atob(message.request.challenge), function (c) { return c.charCodeAt(0) })
|
||||
message.request.user.id = Uint8Array.from(atob(message.request.user.id), function (c) { return c.charCodeAt(0) })
|
||||
navigator.credentials.create({ publicKey: publicKey })
|
||||
.then(function(newCredentialInfo) {
|
||||
// Public key credential
|
||||
var r = { rawId: btoa(String.fromCharCode.apply(null, new Uint8Array(newCredentialInfo.rawId))), response: { attestationObject: btoa(String.fromCharCode.apply(null, new Uint8Array(newCredentialInfo.response.attestationObject))), clientDataJSON: btoa(String.fromCharCode.apply(null, new Uint8Array(newCredentialInfo.response.clientDataJSON))) }, type: newCredentialInfo.type };
|
||||
meshserver.send({ action: 'webauthn-endregister', response: r });
|
||||
setDialogMode(0);
|
||||
}).catch((error) => {
|
||||
}, function(error) {
|
||||
// Error
|
||||
setDialogMode(2, "Add Security Key", 1, null, "ERROR: " + error);
|
||||
});
|
||||
|
@ -1562,6 +1594,7 @@
|
|||
masterUpdate(32);
|
||||
}
|
||||
switch (message.event.action) {
|
||||
case 'servertimelinestats': { addServerTimelineStats(message.event.data); break; }
|
||||
case 'accountcreate':
|
||||
case 'accountchange': {
|
||||
// An account was created or changed
|
||||
|
@ -6433,18 +6466,20 @@
|
|||
var x = '', dateHeader = null;
|
||||
for (var i in events) {
|
||||
var event = events[i], time = new Date(event.time);
|
||||
if (time.toLocaleDateString() != dateHeader) {
|
||||
if (dateHeader != null) x += '</table>';
|
||||
x += '<table style=width:100% cellpadding=0 cellspacing=0><tr><td colspan=4 class=DevSt>' + time.toLocaleDateString() + '</td></tr>';
|
||||
dateHeader = time.toLocaleDateString();
|
||||
}
|
||||
var icon = 'si3';
|
||||
if (event.etype == 'user') icon = 'm2';
|
||||
if (event.etype == 'server') icon = 'si3';
|
||||
if (event.msg) {
|
||||
if (time.toLocaleDateString() != dateHeader) {
|
||||
if (dateHeader != null) x += '</table>';
|
||||
x += '<table style=width:100% cellpadding=0 cellspacing=0><tr><td colspan=4 class=DevSt>' + time.toLocaleDateString() + '</td></tr>';
|
||||
dateHeader = time.toLocaleDateString();
|
||||
}
|
||||
var icon = 'si3';
|
||||
if (event.etype == 'user') icon = 'm2';
|
||||
if (event.etype == 'server') icon = 'si3';
|
||||
|
||||
var msg = event.msg.split('(R)').join('®');
|
||||
if (event.username && event.username != userinfo.name) { msg += ': ' + event.username; }
|
||||
x += '<tr onmouseover=eventMouseHover(this,1) onmouseout=eventMouseHover(this,0) style=cursor:pointer><td style=width:18px><div class=' + icon + '></div></td><td class=g1 style=float:none> </td><td style=background-color:#C9C9C9>' + time.toLocaleTimeString() + ' - ' + msg + '</td><td class=g2 style=float:none> </td></tr><tr style=height:2px></tr>';
|
||||
var msg = event.msg.split('(R)').join('®');
|
||||
if (event.username && event.username != userinfo.name) { msg += ': ' + event.username; }
|
||||
x += '<tr onmouseover=eventMouseHover(this,1) onmouseout=eventMouseHover(this,0) style=cursor:pointer><td style=width:18px><div class=' + icon + '></div></td><td class=g1 style=float:none> </td><td style=background-color:#C9C9C9>' + time.toLocaleTimeString() + ' - ' + msg + '</td><td class=g2 style=float:none> </td></tr><tr style=height:2px></tr>';
|
||||
}
|
||||
}
|
||||
if (dateHeader != null) x += '</table>';
|
||||
if (x == '') x = "<br><i>No Events Found</i><br><br>";
|
||||
|
@ -7169,10 +7204,10 @@
|
|||
}
|
||||
|
||||
//
|
||||
// Server Statistics
|
||||
// MyServer General
|
||||
//
|
||||
|
||||
function setupServerStats() {
|
||||
function setupGeneralServerStats() {
|
||||
window.serverStatCpu = new Chart(document.getElementById('serverCpuChart').getContext('2d'), {
|
||||
type: 'doughnut',
|
||||
data: { datasets: [{ data: [0, 0], backgroundColor: ['#AAAAAA', '#00AA00'] }], labels: ['Used', 'Free'] },
|
||||
|
@ -7186,7 +7221,7 @@
|
|||
}
|
||||
|
||||
var lastServerStats = null;
|
||||
function updateServerStats(message) {
|
||||
function updateGeneralServerStats(message) {
|
||||
if (message != null) { lastServerStats = message; } else { message = lastServerStats; }
|
||||
if (message == null) return;
|
||||
|
||||
|
@ -7220,6 +7255,131 @@
|
|||
QH('serverStatsTable', x);
|
||||
}
|
||||
|
||||
//
|
||||
// MyServer Stats
|
||||
//
|
||||
|
||||
var serverTimelineStats = null;
|
||||
var serverTimelineConfig = {
|
||||
type: 'line',
|
||||
data: { labels: [], datasets: [{ label: '', backgroundColor: 'rgba(255, 99, 132, .5)', borderColor: 'rgb(255, 99, 132)', data: [], fill: true }] },
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
scales: {
|
||||
xAxes: [{ type: 'time', time: { tooltipFormat: 'll HH:mm' }, display: true, scaleLabel: { display: false, labelString: '' } }],
|
||||
yAxes: [{ type: 'linear', display: true, scaleLabel: { display: true, labelString: '' } }]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function refreshServerTimelineStats(stats) { meshserver.send({ action: 'servertimelinestats', hours: 24 }); }
|
||||
function pastDate(hours) { var t = new Date(); t.setTime(t.getTime() - (60 * 60 * 1000 * hours)); return t; }
|
||||
function setServerTimelineStats(stats) { serverTimelineStats = stats; updateServerTimelineStats(); }
|
||||
function addServerTimelineStats(stats) {
|
||||
if (serverTimelineStats == null) return;
|
||||
serverTimelineStats.push(stats);
|
||||
var chartType = Q('p40type').value;
|
||||
if (chartType == 0) {
|
||||
serverTimelineConfig.data.datasets[0].data.push({ x: stats.time, y: stats.conn.ca });
|
||||
serverTimelineConfig.data.datasets[1].data.push({ x: stats.time, y: stats.conn.cu });
|
||||
serverTimelineConfig.data.datasets[2].data.push({ x: stats.time, y: stats.conn.us });
|
||||
serverTimelineConfig.data.datasets[3].data.push({ x: stats.time, y: stats.conn.rs });
|
||||
if (stats.conn.am != null) { serverTimelineConfig.data.datasets[4].data.push({ x: stats.time, y: stats.conn.am }); }
|
||||
} else if (chartType == 1) {
|
||||
serverTimelineConfig.data.datasets[0].data.push({ x: stats.time, y: stats.mem.external / (1024 * 1024) });
|
||||
serverTimelineConfig.data.datasets[1].data.push({ x: stats.time, y: stats.mem.heapUsed / (1024 * 1024) });
|
||||
serverTimelineConfig.data.datasets[2].data.push({ x: stats.time, y: stats.mem.heapTotal / (1024 * 1024) });
|
||||
serverTimelineConfig.data.datasets[3].data.push({ x: stats.time, y: stats.mem.rss / (1024 * 1024) });
|
||||
} /* else if (chartType == 2) {
|
||||
serverTimelineConfig.data.datasets[0].data.push({ x: stats.time, y: stats.db.meshes });
|
||||
serverTimelineConfig.data.datasets[1].data.push({ x: stats.time, y: stats.db.nodes });
|
||||
serverTimelineConfig.data.datasets[2].data.push({ x: stats.time, y: stats.db.users });
|
||||
serverTimelineConfig.data.datasets[3].data.push({ x: stats.time, y: stats.db.total });
|
||||
} */
|
||||
updateServerTimelineHours();
|
||||
}
|
||||
function updateServerTimelineHours() {
|
||||
serverTimelineConfig.options.scales.yAxes[0].type = (Q('p40log').checked ? 'logarithmic' : 'linear');
|
||||
serverTimelineConfig.options.scales.xAxes[0].time = { min: pastDate(Q('p40time').value) };
|
||||
window.serverMainStats.update();
|
||||
}
|
||||
function setupServerTimelineStats() { window.serverMainStats = new Chart(document.getElementById('serverMainStats').getContext('2d'), serverTimelineConfig); }
|
||||
|
||||
function updateServerTimelineStats() {
|
||||
var data, chartType = Q('p40type').value, timeAfter = pastDate(Q('p40time').value);
|
||||
serverTimelineConfig.options.scales.xAxes[0].time = { min: timeAfter };
|
||||
if (chartType == 0) { // Connections
|
||||
serverTimelineConfig.options.scales.yAxes[0].scaleLabel.labelString = 'Connection Count';
|
||||
data = {
|
||||
labels: [pastDate(0), timeAfter],
|
||||
datasets: [
|
||||
{ label: 'Agents', data: [], backgroundColor: 'rgba(158, 151, 16, .1)', borderColor: 'rgb(158, 151, 16)', fill: true },
|
||||
{ label: 'Users', data: [], backgroundColor: 'rgba(16, 84, 158, .1)', borderColor: 'rgb(16, 84, 158)', fill: true },
|
||||
{ label: 'User Sessions', data: [], backgroundColor: 'rgba(255, 99, 132, .1)', borderColor: 'rgb(255, 99, 132)', fill: true },
|
||||
{ label: 'Relay Sessions', data: [], backgroundColor: 'rgba(39, 158, 16, .1)', borderColor: 'rgb(39, 158, 16)', fill: true },
|
||||
{ label: 'Intel AMT', data: [], backgroundColor: 'rgba(134, 16, 158, .1)', borderColor: 'rgb(134, 16, 158)', fill: true }
|
||||
]
|
||||
};
|
||||
for (var i = 0; i < serverTimelineStats.length; i++) {
|
||||
var t = new Date(serverTimelineStats[i].time);
|
||||
if (serverTimelineStats[i].conn) {
|
||||
data.datasets[0].data.push({ x: serverTimelineStats[i].time, y: serverTimelineStats[i].conn.ca });
|
||||
data.datasets[1].data.push({ x: serverTimelineStats[i].time, y: serverTimelineStats[i].conn.cu });
|
||||
data.datasets[2].data.push({ x: serverTimelineStats[i].time, y: serverTimelineStats[i].conn.us });
|
||||
data.datasets[3].data.push({ x: serverTimelineStats[i].time, y: serverTimelineStats[i].conn.rs });
|
||||
if (serverTimelineStats[i].conn.am != null) { data.datasets[4].data.push({ x: serverTimelineStats[i].time, y: serverTimelineStats[i].conn.am }); }
|
||||
}
|
||||
}
|
||||
} else if (chartType == 1) { // Memory
|
||||
serverTimelineConfig.options.scales.yAxes[0].scaleLabel.labelString = 'Megabytes';
|
||||
data = {
|
||||
labels: [pastDate(0), timeAfter],
|
||||
datasets: [
|
||||
{ label: 'External', data: [], backgroundColor: 'rgba(158, 151, 16, .1)', borderColor: 'rgb(158, 151, 16)', fill: true },
|
||||
{ label: 'Heap Used', data: [], backgroundColor: 'rgba(16, 84, 158, .1)', borderColor: 'rgb(16, 84, 158)', fill: true },
|
||||
{ label: 'Heap Total', data: [], backgroundColor: 'rgba(255, 99, 132, .1)', borderColor: 'rgb(255, 99, 132)', fill: true },
|
||||
{ label: 'RSS', data: [], backgroundColor: 'rgba(39, 158, 16, .1)', borderColor: 'rgb(39, 158, 16)', fill: true }
|
||||
]
|
||||
};
|
||||
for (var i = 0; i < serverTimelineStats.length; i++) {
|
||||
data.datasets[0].data.push({ x: serverTimelineStats[i].time, y: serverTimelineStats[i].mem.external / (1024 * 1024) });
|
||||
data.datasets[1].data.push({ x: serverTimelineStats[i].time, y: serverTimelineStats[i].mem.heapUsed / (1024 * 1024) });
|
||||
data.datasets[2].data.push({ x: serverTimelineStats[i].time, y: serverTimelineStats[i].mem.heapTotal / (1024 * 1024) });
|
||||
data.datasets[3].data.push({ x: serverTimelineStats[i].time, y: serverTimelineStats[i].mem.rss / (1024 * 1024) });
|
||||
}
|
||||
} /*else if (chartType == 2) { // Database
|
||||
serverTimelineConfig.options.scales.yAxes[0].scaleLabel.labelString = 'Records';
|
||||
data = {
|
||||
labels: [pastDate(0), timeAfter],
|
||||
datasets: [
|
||||
{ label: 'Groups', data: [], backgroundColor: 'rgba(158, 151, 16, .1)', borderColor: 'rgb(158, 151, 16)', fill: true },
|
||||
{ label: 'Devices', data: [], backgroundColor: 'rgba(16, 84, 158, .1)', borderColor: 'rgb(16, 84, 158)', fill: true },
|
||||
{ label: 'Users', data: [], backgroundColor: 'rgba(255, 99, 132, .1)', borderColor: 'rgb(255, 99, 132)', fill: true },
|
||||
{ label: 'Records', data: [], backgroundColor: 'rgba(39, 158, 16, .1)', borderColor: 'rgb(39, 158, 16)', fill: true }
|
||||
]
|
||||
};
|
||||
for (var i = 0; i < serverTimelineStats.length; i++) {
|
||||
data.datasets[0].data.push({ x: serverTimelineStats[i].time, y: serverTimelineStats[i].db.meshes });
|
||||
data.datasets[1].data.push({ x: serverTimelineStats[i].time, y: serverTimelineStats[i].db.nodes });
|
||||
data.datasets[2].data.push({ x: serverTimelineStats[i].time, y: serverTimelineStats[i].db.users });
|
||||
data.datasets[3].data.push({ x: serverTimelineStats[i].time, y: serverTimelineStats[i].db.total });
|
||||
}
|
||||
}*/
|
||||
serverTimelineConfig.data = data;
|
||||
window.serverMainStats.update();
|
||||
}
|
||||
|
||||
function p40downloadEvents() {
|
||||
var csv = "time, conn.agent, conn.users, conn.usersessions, conn.relaysession, conn.intelamt, mem.external, mem.heapused, mem.heaptotal, mem.rss\r\n";
|
||||
for (var i = 0; i < serverTimelineStats.length; i++) {
|
||||
if (serverTimelineStats[i].conn && serverTimelineStats[i].mem) {
|
||||
csv += new Date(serverTimelineStats[i].time) + ', ' + serverTimelineStats[i].conn.ca + ', ' + serverTimelineStats[i].conn.cu + ', ' + serverTimelineStats[i].conn.us + ', ' + serverTimelineStats[i].conn.rs + ', ' + (serverTimelineStats[i].conn.am ? serverTimelineStats[i].conn.am : '') + ', ' + serverTimelineStats[i].mem.external + ', ' + serverTimelineStats[i].mem.heapUsed + ', ' + serverTimelineStats[i].mem.heapTotal + ', ' + serverTimelineStats[i].mem.rss + '\r\n';
|
||||
}
|
||||
}
|
||||
saveAs(new Blob([csv], { type: "application/octet-stream" }), "ServerStats.csv");
|
||||
}
|
||||
|
||||
//
|
||||
// POPUP DIALOG
|
||||
//
|
||||
|
@ -7274,7 +7434,7 @@
|
|||
function go(x) {
|
||||
if (xxdialogMode || xxcurrentView == x) return;
|
||||
// Edit this line when adding a new screen
|
||||
for (var i = 0; i < 32; i++) { QV('p' + i, i == x); }
|
||||
for (var i = 0; i < 41; i++) { QV('p' + i, i == x); }
|
||||
xxcurrentView = x;
|
||||
|
||||
// Remove left bar selection
|
||||
|
@ -7307,7 +7467,7 @@
|
|||
|
||||
// My Server
|
||||
QS('MainMenuMyServer').backgroundColor = (((x == 6) || (x == 115)) ? "#003366" : "#808080");
|
||||
if (((x == 6) || (x == 115))) { Q('LeftMenuMyServer').classList.add('lbbuttonsel', 'lbbuttonsel2'); }
|
||||
if (((x == 6) || (x == 115) || (x == 40))) { Q('LeftMenuMyServer').classList.add('lbbuttonsel', 'lbbuttonsel2'); }
|
||||
|
||||
// column_l max-height
|
||||
if (webPageFullScreen) {
|
||||
|
@ -7326,8 +7486,8 @@
|
|||
QV('UserDummyMenuSpan', (x < 10) && (x != 6) && webPageFullScreen);
|
||||
QV('MeshSubMenuSpan', x >= 20 && x < 30);
|
||||
QV('UserSubMenuSpan', x >= 30 && x < 40);
|
||||
QV('ServerSubMenuSpan', x == 6 || x == 115);
|
||||
var panels = { 10: 'MainDev', 11: 'MainDevDesktop', 12: 'MainDevTerminal', 13: 'MainDevFiles', 14: 'MainDevAmt', 15: 'MainDevConsole', 20: 'MeshGeneral', 30: 'UserGeneral', 31: 'UserEvents', 6: 'ServerGeneral', 115: 'ServerConsole' };
|
||||
QV('ServerSubMenuSpan', x == 6 || x == 115 || x == 40);
|
||||
var panels = { 10: 'MainDev', 11: 'MainDevDesktop', 12: 'MainDevTerminal', 13: 'MainDevFiles', 14: 'MainDevAmt', 15: 'MainDevConsole', 20: 'MeshGeneral', 30: 'UserGeneral', 31: 'UserEvents', 6: 'ServerGeneral', 40: 'ServerStats', 115: 'ServerConsole' };
|
||||
for (var i in panels) {
|
||||
Q(panels[i]).classList.remove('style3x');
|
||||
Q(panels[i]).classList.remove('style3sel');
|
||||
|
@ -7342,6 +7502,9 @@
|
|||
|
||||
if (x == 1) masterUpdate(4);
|
||||
|
||||
// Fetch the server timeline stats if needed
|
||||
if ((x == 40) && (serverTimelineStats == null)) { refreshServerTimelineStats(); }
|
||||
|
||||
// Update the web page title
|
||||
if ((currentNode) && (x >= 10) && (x < 20)) { document.title = 'MeshCentral - ' + currentNode.name; } else { document.title = 'MeshCentral'; }
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -260,7 +260,7 @@
|
|||
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 = '{{{hkey}}}';
|
||||
var hardwareKeyChallenge = decodeURIComponent('{{{hkey}}}');
|
||||
var currentpanel = 0;
|
||||
|
||||
function startup() {
|
||||
|
@ -287,7 +287,34 @@
|
|||
|
||||
if ('{{loginmode}}' == '4') {
|
||||
try { if (hardwareKeyChallenge.length > 0) { hardwareKeyChallenge = JSON.parse(hardwareKeyChallenge); } else { hardwareKeyChallenge = null; } } catch (ex) { hardwareKeyChallenge = null }
|
||||
if ((hardwareKeyChallenge != null) && u2fSupported()) {
|
||||
if ((hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn')) {
|
||||
hardwareKeyChallenge.challenge = Uint8Array.from(atob(hardwareKeyChallenge.challenge), function (c) { return c.charCodeAt(0) }).buffer;
|
||||
|
||||
var 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); }
|
||||
);
|
||||
} else if ((hardwareKeyChallenge != null) && u2fSupported()) {
|
||||
// Old U2F hardware keys
|
||||
window.u2f.sign(hardwareKeyChallenge.appId, hardwareKeyChallenge.challenge, hardwareKeyChallenge.registeredKeys, function (authResponse) {
|
||||
if ((currentpanel == 4) && authResponse.signatureData) {
|
||||
Q('hwtokenInput').value = JSON.stringify(authResponse);
|
||||
|
@ -300,7 +327,34 @@
|
|||
|
||||
if ('{{loginmode}}' == '5') {
|
||||
try { if (hardwareKeyChallenge.length > 0) { hardwareKeyChallenge = JSON.parse(hardwareKeyChallenge); } else { hardwareKeyChallenge = null; } } catch (ex) { hardwareKeyChallenge = null }
|
||||
if ((hardwareKeyChallenge != null) && u2fSupported()) {
|
||||
if ((hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn')) {
|
||||
hardwareKeyChallenge.challenge = Uint8Array.from(atob(hardwareKeyChallenge.challenge), function (c) { return c.charCodeAt(0) }).buffer;
|
||||
|
||||
var 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('resetHwtokenInput').value = JSON.stringify(assertion);
|
||||
QE('resetTokenOkButton', true);
|
||||
Q('resetTokenOkButton').click();
|
||||
},
|
||||
function (error) { console.log('credentials-get error', error); }
|
||||
);
|
||||
} else if ((hardwareKeyChallenge != null) && u2fSupported()) {
|
||||
// Old U2F hardware keys
|
||||
window.u2f.sign(hardwareKeyChallenge.appId, hardwareKeyChallenge.challenge, hardwareKeyChallenge.registeredKeys, function (authResponse) {
|
||||
if ((currentpanel == 5) && authResponse.signatureData) {
|
||||
Q('resetHwtokenInput').value = JSON.stringify(authResponse);
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<meta name="format-detection" content="telephone=no" />
|
||||
<link type="text/css" href="styles/style.css" media="screen" rel="stylesheet" title="CSS" />
|
||||
<script type="text/javascript" src="scripts/common-0.0.1.js"></script>
|
||||
<script type="text/javascript" src="scripts/u2f-api.js"></script>
|
||||
<script keeplink=1 type="text/javascript" src="scripts/u2f-api.js"></script>
|
||||
<title>{{{title}}} - Login</title>
|
||||
</head>
|
||||
<body id="body" onload="if (typeof(startup) !== 'undefined') startup();" class="arg_hide">
|
||||
|
@ -27,7 +27,7 @@
|
|||
<div id="welcomeText" style="display:none">Connect to your home or office devices from anywhere in the world using <a href="http://www.meshcommander.com/meshcentral2">MeshCentral</a>, the real time, open source remote monitoring and management web site. You will need to download and install a management agent on your computers. Once installed, computers will show up in the "My Devices" section of this web site and you will be able to monitor them and take control of them.</div>
|
||||
<table id="centralTable" style="">
|
||||
<tr>
|
||||
<td id="welcomeimage">
|
||||
<td id="welcomeimage" style="display:none">
|
||||
<picture>
|
||||
<img alt="" src=welcome.jpg />
|
||||
</picture>
|
||||
|
@ -243,7 +243,7 @@
|
|||
var newAccountPass = parseInt('{{{newAccountPass}}}');
|
||||
var emailCheck = ('{{{emailcheck}}}' == 'true');
|
||||
var passRequirements = "{{{passRequirements}}}";
|
||||
var hardwareKeyChallenge = '{{{hkey}}}';
|
||||
var hardwareKeyChallenge = decodeURIComponent('{{{hkey}}}');
|
||||
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 features = parseInt('{{{features}}}');
|
||||
|
@ -284,12 +284,12 @@
|
|||
if ('{{loginmode}}' == '4') {
|
||||
try { if (hardwareKeyChallenge.length > 0) { hardwareKeyChallenge = JSON.parse(hardwareKeyChallenge); } else { hardwareKeyChallenge = null; } } catch (ex) { hardwareKeyChallenge = null }
|
||||
if ((hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn')) {
|
||||
hardwareKeyChallenge.challenge = Uint8Array.from(atob(hardwareKeyChallenge.challenge), c => c.charCodeAt(0)).buffer;
|
||||
hardwareKeyChallenge.challenge = Uint8Array.from(atob(hardwareKeyChallenge.challenge), function (c) { return c.charCodeAt(0) }).buffer;
|
||||
|
||||
const publicKeyCredentialRequestOptions = { challenge: hardwareKeyChallenge.challenge, allowCredentials: [], timeout: hardwareKeyChallenge.timeout }
|
||||
var 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]), c => c.charCodeAt(0)), type: 'public-key', transports: ['usb', 'ble', 'nfc'], }
|
||||
{ id: Uint8Array.from(atob(hardwareKeyChallenge.keyIds[i]), function (c) { return c.charCodeAt(0) }), type: 'public-key', transports: ['usb', 'ble', 'nfc'], }
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -297,11 +297,11 @@
|
|||
navigator.credentials.get({ publicKey: publicKeyCredentialRequestOptions }).then(
|
||||
function (rawAssertion) {
|
||||
var assertion = {
|
||||
id: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.rawId))), //base64encode(rawAssertion.rawId),
|
||||
clientDataJSON: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.clientDataJSON))), //arrayBufferToString(rawAssertion.response.clientDataJSON),
|
||||
userHandle: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.userHandle))), //base64encode(rawAssertion.response.userHandle),
|
||||
signature: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.signature))), //base64encode(rawAssertion.response.signature),
|
||||
authenticatorData: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.authenticatorData))), //base64encode(rawAssertion.response.authenticatorData)
|
||||
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);
|
||||
|
@ -323,7 +323,34 @@
|
|||
|
||||
if ('{{loginmode}}' == '5') {
|
||||
try { if (hardwareKeyChallenge.length > 0) { hardwareKeyChallenge = JSON.parse(hardwareKeyChallenge); } else { hardwareKeyChallenge = null; } } catch (ex) { hardwareKeyChallenge = null }
|
||||
if ((hardwareKeyChallenge != null) && u2fSupported()) {
|
||||
if ((hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn')) {
|
||||
hardwareKeyChallenge.challenge = Uint8Array.from(atob(hardwareKeyChallenge.challenge), function (c) { return c.charCodeAt(0) }).buffer;
|
||||
|
||||
var 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('resetHwtokenInput').value = JSON.stringify(assertion);
|
||||
QE('resetTokenOkButton', true);
|
||||
Q('resetTokenOkButton').click();
|
||||
},
|
||||
function (error) { console.log('credentials-get error', error); }
|
||||
);
|
||||
} else if ((hardwareKeyChallenge != null) && u2fSupported()) {
|
||||
// Old U2F hardware keys
|
||||
window.u2f.sign(hardwareKeyChallenge.appId, hardwareKeyChallenge.challenge, hardwareKeyChallenge.registeredKeys, function (authResponse) {
|
||||
if ((currentpanel == 5) && authResponse.signatureData) {
|
||||
Q('resetHwtokenInput').value = JSON.stringify(authResponse);
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -560,8 +560,7 @@
|
|||
displayLocalVideo(true);
|
||||
}
|
||||
for (var i in tracks) { webrtc.addTrack(tracks[i], localStream); }
|
||||
})
|
||||
.catch(function (err) {
|
||||
}, function (err) {
|
||||
displayControl(err.message + '.');
|
||||
hangUpButtonClick(1);
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue