Added deviceinfo support to meshCtrl.

This commit is contained in:
Ylian Saint-Hilaire 2020-05-02 13:49:56 -07:00
parent 793e1a706b
commit b91bf8579a
6 changed files with 253 additions and 11 deletions

View File

@ -7,7 +7,7 @@ try { require('ws'); } catch (ex) { console.log('Missing module "ws", type "npm
var settings = {}; var settings = {};
const crypto = require('crypto'); const crypto = require('crypto');
const args = require('minimist')(process.argv.slice(2)); const args = require('minimist')(process.argv.slice(2));
const possibleCommands = ['listusers', 'listdevicegroups', 'listdevices', 'listusersofdevicegroup', 'serverinfo', 'userinfo', 'adduser', 'removeuser', 'adddevicegroup', 'removedevicegroup', 'broadcast', 'showevents', 'addusertodevicegroup', 'removeuserfromdevicegroup', 'addusertodevice', 'removeuserfromdevice', 'sendinviteemail', 'generateinvitelink', 'config', 'movetodevicegroup']; const possibleCommands = ['listusers', 'listdevicegroups', 'listdevices', 'listusersofdevicegroup', 'serverinfo', 'userinfo', 'adduser', 'removeuser', 'adddevicegroup', 'removedevicegroup', 'broadcast', 'showevents', 'addusertodevicegroup', 'removeuserfromdevicegroup', 'addusertodevice', 'removeuserfromdevice', 'sendinviteemail', 'generateinvitelink', 'config', 'movetodevicegroup', 'deviceinfo'];
if (args.proxy != null) { try { require('https-proxy-agent'); } catch (ex) { console.log('Missing module "https-proxy-agent", type "npm install https-proxy-agent" to install it.'); return; } } if (args.proxy != null) { try { require('https-proxy-agent'); } catch (ex) { console.log('Missing module "https-proxy-agent", type "npm install https-proxy-agent" to install it.'); return; } }
if (args['_'].length == 0) { if (args['_'].length == 0) {
@ -22,6 +22,7 @@ if (args['_'].length == 0) {
console.log(" ListDevices - List devices."); console.log(" ListDevices - List devices.");
console.log(" ListDeviceGroups - List device groups."); console.log(" ListDeviceGroups - List device groups.");
console.log(" ListUsersOfDeviceGroup - List the users in a device group."); console.log(" ListUsersOfDeviceGroup - List the users in a device group.");
console.log(" DeviceInfo - Show information about a device.");
console.log(" Config - Perform operation on config.json file."); console.log(" Config - Perform operation on config.json file.");
console.log(" AddUser - Create a new user account."); console.log(" AddUser - Create a new user account.");
console.log(" RemoveUser - Delete a user account."); console.log(" RemoveUser - Delete a user account.");
@ -64,6 +65,11 @@ if (args['_'].length == 0) {
else { ok = true; } else { ok = true; }
break; break;
} }
case 'deviceinfo': {
if (args.id == null) { console.log("Missing device id, use --id [deviceid]"); }
else { ok = true; }
break;
}
case 'addusertodevicegroup': { case 'addusertodevicegroup': {
if ((args.id == null) && (args.group == null)) { console.log("Device group identifier missing, use --id [groupid] or --group [groupname]"); } if ((args.id == null) && (args.group == null)) { console.log("Device group identifier missing, use --id [groupid] or --group [groupname]"); }
else if (args.userid == null) { console.log("Add user to group missing useid, use --userid [userid]"); } else if (args.userid == null) { console.log("Add user to group missing useid, use --userid [userid]"); }
@ -364,6 +370,17 @@ if (args['_'].length == 0) {
console.log(" --msg [message] - Message to display."); console.log(" --msg [message] - Message to display.");
break; break;
} }
case 'deviceinfo': {
console.log("Display information about a device, Example usages:\r\n");
console.log(" MeshCtrl DeviceInfo --id deviceid");
console.log(" MeshCtrl DeviceInfo --id deviceid --json");
console.log("\r\nRequired arguments:\r\n");
console.log(" --id [deviceid] - The device identifier.");
console.log("\r\nOptional arguments:\r\n");
console.log(" --raw - Output raw data in JSON format.");
console.log(" --json - Give results in JSON format.");
break;
}
default: { default: {
console.log("Get help on an action. Type:\r\n\r\n help [action]\r\n\r\nPossible actions are: " + possibleCommands.join(', ') + '.'); console.log("Get help on an action. Type:\r\n\r\n help [action]\r\n\r\nPossible actions are: " + possibleCommands.join(', ') + '.');
} }
@ -696,6 +713,13 @@ function serverConnect() {
console.log('Connected. Press ctrl-c to end.'); console.log('Connected. Press ctrl-c to end.');
break; break;
} }
case 'deviceinfo': {
settings.deviceinfocount = 3;
ws.send(JSON.stringify({ action: 'getnetworkinfo', nodeid: args.id, nodeinfo: true, responseid: 'meshctrl' }));
ws.send(JSON.stringify({ action: 'lastconnect', nodeid: args.id, nodeinfo: true, responseid: 'meshctrl' }));
ws.send(JSON.stringify({ action: 'getsysinfo', nodeid: args.id, nodeinfo: true, responseid: 'meshctrl' }));
break;
}
} }
}); });
@ -738,6 +762,32 @@ function serverConnect() {
} }
break; break;
} }
case 'getsysinfo': { // DEVICEINFO
if (settings.cmd == 'deviceinfo') {
if (data.result) {
console.log(data.result);
process.exit();
} else {
settings.sysinfo = data;
if (--settings.deviceinfocount == 0) { displayDeviceInfo(settings.sysinfo, settings.lastconnect, settings.networking); process.exit(); }
}
}
break;
}
case 'lastconnect': {
if (settings.cmd == 'deviceinfo') {
settings.lastconnect = (data.result)?null:data;
if (--settings.deviceinfocount == 0) { displayDeviceInfo(settings.sysinfo, settings.lastconnect, settings.networking); process.exit(); }
}
break;
}
case 'getnetworkinfo': {
if (settings.cmd == 'deviceinfo') {
settings.networking = (data.result) ? null : data;
if (--settings.deviceinfocount == 0) { displayDeviceInfo(settings.sysinfo, settings.lastconnect, settings.networking); process.exit(); }
}
break;
}
case 'adduser': // ADDUSER case 'adduser': // ADDUSER
case 'deleteuser': // REMOVEUSER case 'deleteuser': // REMOVEUSER
case 'createmesh': // ADDDEVICEGROUP case 'createmesh': // ADDDEVICEGROUP
@ -919,3 +969,155 @@ function encodeCookie(o, key) {
// Generate a random Intel AMT password // Generate a random Intel AMT password
function checkAmtPassword(p) { return (p.length > 7) && (/\d/.test(p)) && (/[a-z]/.test(p)) && (/[A-Z]/.test(p)) && (/\W/.test(p)); } function checkAmtPassword(p) { return (p.length > 7) && (/\d/.test(p)) && (/[a-z]/.test(p)) && (/[A-Z]/.test(p)) && (/\W/.test(p)); }
function getRandomAmtPassword() { var p; do { p = Buffer.from(crypto.randomBytes(9), 'binary').toString('base64').split('/').join('@'); } while (checkAmtPassword(p) == false); return p; } function getRandomAmtPassword() { var p; do { p = Buffer.from(crypto.randomBytes(9), 'binary').toString('base64').split('/').join('@'); } while (checkAmtPassword(p) == false); return p; }
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; }); };
function displayDeviceInfo(sysinfo, lastconnect, network) {
var node = sysinfo.node;
var hardware = sysinfo.hardware;
var info = {};
if (network != null) { sysinfo.netif = network.netif; }
if (lastconnect != null) { node.lastconnect = lastconnect.time; node.lastaddr = lastconnect.addr; }
if (args.raw) { console.log(JSON.stringify(sysinfo, ' ', 2)); return; }
// Operating System
if ((hardware.windows && hardware.windows.osinfo) || node.osdesc) {
var output = {}, outputCount = 0;
if (node.rname) { output["Name"] = node.rname; outputCount++; }
if (node.osdesc) { output["Version"] = node.osdesc; outputCount++; }
if (hardware.windows && hardware.windows.osinfo) { var m = hardware.windows.osinfo; if (m.OSArchitecture) { output["Architecture"] = m.OSArchitecture; outputCount++; } }
if (outputCount > 0) { info["Operating System"] = output; }
}
// MeshAgent
if (node.agent) {
var output = {}, outputCount = 0;
var agentsStr = ["Unknown", "Windows 32bit console", "Windows 64bit console", "Windows 32bit service", "Windows 64bit service", "Linux 32bit", "Linux 64bit", "MIPS", "XENx86", "Android ARM", "Linux ARM", "MacOS 32bit", "Android x86", "PogoPlug ARM", "Android APK", "Linux Poky x86-32bit", "MacOS 64bit", "ChromeOS", "Linux Poky x86-64bit", "Linux NoKVM x86-32bit", "Linux NoKVM x86-64bit", "Windows MinCore console", "Windows MinCore service", "NodeJS", "ARM-Linaro", "ARMv6l / ARMv7l", "ARMv8 64bit", "ARMv6l / ARMv7l / NoKVM", "Unknown", "Unknown", "FreeBSD x86-64"];
if ((node.agent != null) && (node.agent.id != null) && (node.agent.ver != null)) {
var str = '';
if (node.agent.id <= agentsStr.length) { str = agentsStr[node.agent.id]; } else { str = agentsStr[0]; }
if (node.agent.ver != 0) { str += ' v' + node.agent.ver; }
output["Mesh Agent"] = str; outputCount++;
}
if ((node.conn & 1) != 0) {
output["Last agent connection"] = "Connected now"; outputCount++;
} else {
if (node.lastconnect) { output["Last agent connection"] = new Date(node.lastconnect).toLocaleString(); outputCount++; }
}
if (node.lastaddr) {
var splitip = node.lastaddr.split(':');
if (splitip.length > 2) {
output["Last agent address"] = node.lastaddr; outputCount++; // IPv6
} else {
output["Last agent address"] = splitip[0]; outputCount++; // IPv4
}
}
if (outputCount > 0) { info["Mesh Agent"] = output; }
}
// Networking
if (network.netif != null) {
var output = {}, outputCount = 0, minfo = {};
for (var i in network.netif) {
var m = network.netif[i], moutput = {}, moutputCount = 0;
if (m.desc) { moutput["Description"] = m.desc; moutputCount++; }
if (m.mac) {
if (m.gatewaymac) {
moutput["MAC Layer"] = format("MAC: {0}, Gateway: {1}", m.mac, m.gatewaymac); moutputCount++;
} else {
moutput["MAC Layer"] = format("MAC: {0}", m.mac); moutputCount++;
}
}
if (m.v4addr && (m.v4addr != '0.0.0.0')) {
if (m.v4gateway && m.v4mask) {
moutput["IPv4 Layer"] = format("IP: {0}, Mask: {1}, Gateway: {2}", m.v4addr, m.v4mask, m.v4gateway); moutputCount++;
} else {
moutput["IPv4 Layer"] = format("IP: {0}", m.v4addr); moutputCount++;
}
}
if (moutputCount > 0) { minfo[m.name + (m.dnssuffix ? (', ' + m.dnssuffix) : '')] = moutput; info["Networking"] = minfo; }
}
}
// Intel AMT
if (node.intelamt != null) {
var output = {}, outputCount = 0;
output["Version"] = (node.intelamt.ver) ? ('v' + node.intelamt.ver) : ('<i>' + "Unknown" + '</i>'); outputCount++;
var provisioningStates = { 0: "Not Activated (Pre)", 1: "Not Activated (In)", 2: "Activated" };
var provisioningMode = '';
if ((node.intelamt.state == 2) && node.intelamt.flags) { if (node.intelamt.flags & 2) { provisioningMode = (', ' + "Client Control Mode (CCM)"); } else if (node.intelamt.flags & 4) { provisioningMode = (', ' + "Admin Control Mode (ACM)"); } }
output["Provisioning State"] = ((node.intelamt.state) ? (provisioningStates[node.intelamt.state]) : ('<i>' + "Unknown" + '</i>')) + provisioningMode; outputCount++;
output["Security"] = (node.intelamt.tls == 1) ? "Secured using TLS" : "TLS is not setup"; outputCount++;
output["Admin Credentials"] = (node.intelamt.user == null || node.intelamt.user == '') ? "Not Known" : "Known"; outputCount++;
if (outputCount > 0) { info["Intel Active Management Technology (Intel AMT)"] = output; }
}
if (hardware.identifiers) {
var output = {}, outputCount = 0, ident = hardware.identifiers;
// BIOS
if (ident.bios_vendor) { output["Vendor"] = ident.bios_vendor; outputCount++; }
if (ident.bios_version) { output["Version"] = ident.bios_version; outputCount++; }
if (outputCount > 0) { info["BIOS"] = output; }
output = {}, outputCount = 0;
// Motherboard
if (ident.board_vendor) { output["Vendor"] = ident.board_vendor; outputCount++; }
if (ident.board_name) { output["Name"] = ident.board_name; outputCount++; }
if (ident.board_serial && (ident.board_serial != '')) { output["Serial"] = ident.board_serial; outputCount++; }
if (ident.board_version) { output["Version"] = ident.board_version; }
if (ident.product_uuid) { output["Identifier"] = ident.product_uuid; }
if (ident.cpu_name) { output["CPU"] = ident.cpu_name; }
if (ident.gpu_name) { for (var i in ident.gpu_name) { output["GPU" + (parseInt(i) + 1)] = ident.gpu_name[i]; } }
if (outputCount > 0) { info["Motherboard"] = output; }
}
// Memory
if (hardware.windows) {
if (hardware.windows.memory) {
var output = {}, outputCount = 0, minfo = {};
hardware.windows.memory.sort(function (a, b) { if (a.BankLabel > b.BankLabel) return 1; if (a.BankLabel < b.BankLabel) return -1; return 0; });
for (var i in hardware.windows.memory) {
var m = hardware.windows.memory[i], moutput = {}, moutputCount = 0;
if (m.Capacity) { moutput["Capacity/Speed"] = (m.Capacity / 1024 / 1024) + " Mb, " + m.Speed + " Mhz"; moutputCount++; }
if (m.PartNumber) { moutput["Part Number"] = ((m.Manufacturer && m.Manufacturer != 'Undefined') ? (m.Manufacturer + ', ') : '') + m.PartNumber; moutputCount++; }
if (moutputCount > 0) { minfo[m.BankLabel] = moutput; info["Memory"] = minfo; }
}
}
}
// Storage
if (hardware.identifiers && ident.storage_devices) {
var output = {}, outputCount = 0, minfo = {};
// Sort Storage
ident.storage_devices.sort(function (a, b) { if (a.Caption > b.Caption) return 1; if (a.Caption < b.Caption) return -1; return 0; });
for (var i in ident.storage_devices) {
var m = ident.storage_devices[i], moutput = {};
if (m.Size) {
if (m.Model && (m.Model != m.Caption)) { moutput["Model"] = m.Model; outputCount++; }
if ((typeof m.Size == 'string') && (parseInt(m.Size) == m.Size)) { m.Size = parseInt(m.Size); }
if (typeof m.Size == 'number') { moutput["Capacity"] = Math.floor(m.Size / 1024 / 1024) + 'Mb'; outputCount++; }
if (typeof m.Size == 'string') { moutput["Capacity"] = m.Size; outputCount++; }
if (moutputCount > 0) { minfo[m.Caption] = moutput; info["Storage"] = minfo; }
}
}
}
// Display everything
if (args.json) {
console.log(JSON.stringify(info, ' ', 2));
} else {
for (var i in info) {
console.log('--- ' + i + ' ---');
for (var j in info[i]) {
if (typeof info[i][j] == 'string') {
console.log(' ' + j + ': ' + info[i][j]);
} else {
console.log(' ' + j + ':');
for (var k in info[i][j]) {
console.log(' ' + k + ': ' + info[i][j][k]);
}
}
}
}
}
}

View File

@ -616,9 +616,13 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
} }
case 'getsysinfo': case 'getsysinfo':
{ {
if (common.validateString(command.nodeid, 1, 1024) == false) break; // Check the nodeid
if (command.nodeid.indexOf('/') == -1) { command.nodeid = 'node/' + domain.id + '/' + command.nodeid; }
if ((command.nodeid.split('/').length != 3) || (command.nodeid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
// Get the node and the rights for this node // Get the node and the rights for this node
parent.GetNodeWithRights(domain, user, command.nodeid, function (node, rights, visible) { parent.GetNodeWithRights(domain, user, command.nodeid, function (node, rights, visible) {
if (visible == false) return; if (visible == false) { try { ws.send(JSON.stringify({ action: 'getsysinfo', nodeid: command.nodeid, tag: command.tag, noinfo: true, result: 'Invalid device id' })); } catch (ex) { } return; }
// Query the database system information // Query the database system information
db.Get('si' + command.nodeid, function (err, docs) { db.Get('si' + command.nodeid, function (err, docs) {
if ((docs != null) && (docs.length > 0)) { if ((docs != null) && (docs.length > 0)) {
@ -629,9 +633,10 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
delete doc.type; delete doc.type;
delete doc.domain; delete doc.domain;
delete doc._id; delete doc._id;
if (command.nodeinfo === true) { doc.node = node; doc.rights = rights; }
try { ws.send(JSON.stringify(doc)); } catch (ex) { } try { ws.send(JSON.stringify(doc)); } catch (ex) { }
} else { } else {
try { ws.send(JSON.stringify({ action: 'getsysinfo', nodeid: node._id, tag: command.tag, noinfo: true })); } catch (ex) { } try { ws.send(JSON.stringify({ action: 'getsysinfo', nodeid: node._id, tag: command.tag, noinfo: true, result: 'Invalid device id' })); } catch (ex) { }
} }
}); });
}); });
@ -639,13 +644,20 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
} }
case 'lastconnect': case 'lastconnect':
{ {
if (common.validateString(command.nodeid, 1, 1024) == false) break; // Check the nodeid
if (command.nodeid.indexOf('/') == -1) { command.nodeid = 'node/' + domain.id + '/' + command.nodeid; }
if ((command.nodeid.split('/').length != 3) || (command.nodeid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
// Get the node and the rights for this node // Get the node and the rights for this node
parent.GetNodeWithRights(domain, user, command.nodeid, function (node, rights, visible) { parent.GetNodeWithRights(domain, user, command.nodeid, function (node, rights, visible) {
if (visible == false) return; if (visible == false) { try { ws.send(JSON.stringify({ action: 'lastconnect', nodeid: command.nodeid, tag: command.tag, noinfo: true, result: 'Invalid device id' })); } catch (ex) { } return; }
// Query the database for the last time this node connected // Query the database for the last time this node connected
db.Get('lc' + command.nodeid, function (err, docs) { db.Get('lc' + command.nodeid, function (err, docs) {
if ((docs != null) && (docs.length > 0)) { if ((docs != null) && (docs.length > 0)) {
try { ws.send(JSON.stringify({ action: 'lastconnect', nodeid: command.nodeid, time: docs[0].time, addr: docs[0].addr })); } catch (ex) { } try { ws.send(JSON.stringify({ action: 'lastconnect', nodeid: command.nodeid, time: docs[0].time, addr: docs[0].addr })); } catch (ex) { }
} else {
try { ws.send(JSON.stringify({ action: 'lastconnect', nodeid: command.nodeid, tag: command.tag, noinfo: true, result: 'No data' })); } catch (ex) { }
} }
}); });
}); });
@ -3187,11 +3199,12 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
{ {
// Argument validation // Argument validation
if (common.validateString(command.nodeid, 1, 1024) == false) break; // Check nodeid if (common.validateString(command.nodeid, 1, 1024) == false) break; // Check nodeid
if (command.nodeid.indexOf('/') == -1) { command.nodeid = 'node/' + domain.id + '/' + command.nodeid; }
if ((command.nodeid.split('/').length != 3) || (command.nodeid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain if ((command.nodeid.split('/').length != 3) || (command.nodeid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
// Get the node and the rights for this node // Get the node and the rights for this node
parent.GetNodeWithRights(domain, user, command.nodeid, function (node, rights, visible) { parent.GetNodeWithRights(domain, user, command.nodeid, function (node, rights, visible) {
if (visible == false) return; if (visible == false) { try { ws.send(JSON.stringify({ action: 'getnetworkinfo', nodeid: command.nodeid, tag: command.tag, noinfo: true, result: 'Invalid device id' })); } catch (ex) { } return; }
// Get network information about this node // Get network information about this node
db.Get('if' + node._id, function (err, netinfos) { db.Get('if' + node._id, function (err, netinfos) {

BIN
public/images/icon-film.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 612 B

View File

@ -196,6 +196,7 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) {
if (obj.debugmode > 1) { console.log("KRecv(" + str.length + "): " + rstr2hex(str.substring(0, Math.min(str.length, 40)))); } if (obj.debugmode > 1) { console.log("KRecv(" + str.length + "): " + rstr2hex(str.substring(0, Math.min(str.length, 40)))); }
if (str.length < 4) return; if (str.length < 4) return;
var cmdmsg = null, X = 0, Y = 0, command = ReadShort(str, 0), cmdsize = ReadShort(str, 2), jumboAdd = 0; var cmdmsg = null, X = 0, Y = 0, command = ReadShort(str, 0), cmdsize = ReadShort(str, 2), jumboAdd = 0;
if (obj.recordedData != null) { obj.recordedData.push({ t: Date.now(), d: str }); }
if ((command == 27) && (cmdsize == 8)) { if ((command == 27) && (cmdsize == 8)) {
// Jumbo packet // Jumbo packet
if (str.length < 12) return; if (str.length < 12) return;
@ -777,6 +778,18 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) {
return true; return true;
} }
obj.StartRecording = function () {
obj.recordedData = [];
obj.recordedStart = Date.now();
}
obj.StopRecording = function () {
var r = obj.recordedData;
delete obj.recordedData;
delete obj.recordedStart;
return r;
}
// Private method // Private method
obj.MuchTheSame = function (a, b) { return (Math.abs(a - b) < 4); } obj.MuchTheSame = function (a, b) { return (Math.abs(a - b) < 4); }
obj.Debug = function (msg) { console.log(msg); } obj.Debug = function (msg) { console.log(msg); }

View File

@ -2339,7 +2339,7 @@ a {
-ms-grid-row: 4; -ms-grid-row: 4;
} }
#DeskChatButton, #DeskNotifyButton, #DeskOpenWebButton, #DeskBackgroundButton, #DeskSaveImageButton { #DeskChatButton, #DeskNotifyButton, #DeskOpenWebButton, #DeskBackgroundButton, #DeskSaveImageButton, #DeskRecordButton {
float: right; float: right;
margin-top: 1px; margin-top: 1px;
margin-right: 4px; margin-right: 4px;

View File

@ -572,6 +572,7 @@
<span id=DeskOpenWebButton title="Open a web address on the remote computer"><img src='images/icon-url2.png' onclick=deviceUrlFunction() height=16 width=16 style=padding-top:2px /></span> <span id=DeskOpenWebButton title="Open a web address on the remote computer"><img src='images/icon-url2.png' onclick=deviceUrlFunction() height=16 width=16 style=padding-top:2px /></span>
<span id=DeskBackgroundButton title="Toggle remote desktop background"><img src='images/icon-background.png' onclick=deviceToggleBackground(event) height=16 width=16 style=padding-top:2px /></span> <span id=DeskBackgroundButton title="Toggle remote desktop background"><img src='images/icon-background.png' onclick=deviceToggleBackground(event) height=16 width=16 style=padding-top:2px /></span>
<span id=DeskSaveImageButton title="Save a screenshot of the remote desktop"><img src='images/icon-camera.png' onclick=deskSaveImage() height=16 width=16 style=padding-top:2px /></span> <span id=DeskSaveImageButton title="Save a screenshot of the remote desktop"><img src='images/icon-camera.png' onclick=deskSaveImage() height=16 width=16 style=padding-top:2px /></span>
<span id=DeskRecordButton title="Record remote desktop session to file" style="display:none"><img src='images/icon-film.png' onclick=deskRecordSession() height=16 width=16 style=padding-top:2px /></span>
</div> </div>
<div> <div>
<select id="deskkeys"> <select id="deskkeys">
@ -5759,9 +5760,6 @@
desktopNode = currentNode; desktopNode = currentNode;
updateDesktopButtons(); updateDesktopButtons();
deskAdjust(); deskAdjust();
// On some browsers like IE, we can't save screen shots. Hide the scheenshot/capture buttons.
if (!Q('Desk')['toBlob']) { QV('DeskSaveImageButton', false); }
} }
// Show and enable the right buttons // Show and enable the right buttons
@ -5797,7 +5795,6 @@
QE('connectbutton1', online); QE('connectbutton1', online);
var hwonline = ((currentNode.conn & 6) != 0); // If CIRA (2) or AMT (4) connected, enable hardware terminal var hwonline = ((currentNode.conn & 6) != 0); // If CIRA (2) or AMT (4) connected, enable hardware terminal
QE('connectbutton1h', hwonline); QE('connectbutton1h', hwonline);
QE('DeskSaveImageButton', deskState == 3);
QV('deskFocusBtn', (desktop != null) && (desktop.contype == 2) && (deskState != 0) && (desktopsettings.showfocus)); QV('deskFocusBtn', (desktop != null) && (desktop.contype == 2) && (deskState != 0) && (desktopsettings.showfocus));
QV('DeskClip', (currentNode.agent) && (currentNode.agent.id != 11) && (currentNode.agent.id != 16) && ((desktop == null) || (desktop.contype != 2))); // Clipboard not supported on MacOS QV('DeskClip', (currentNode.agent) && (currentNode.agent.id != 11) && (currentNode.agent.id != 16) && ((desktop == null) || (desktop.contype != 2))); // Clipboard not supported on MacOS
QE('DeskClip', deskState == 3); QE('DeskClip', deskState == 3);
@ -5808,6 +5805,8 @@
QE('deskkeys', deskState == 3); QE('deskkeys', deskState == 3);
// Display this only if we have Chat & Notify permissions // Display this only if we have Chat & Notify permissions
QV('DeskSaveImageButton', (deskState == 3) && (Q('Desk')['toBlob'] != null));
QV('DeskRecordButton', (deskState == 3));
QV('DeskChatButton', ((rights & 16384) != 0) && (browserfullscreen == false) && (inputAllowed) && (currentNode.agent) && online); QV('DeskChatButton', ((rights & 16384) != 0) && (browserfullscreen == false) && (inputAllowed) && (currentNode.agent) && online);
QV('DeskNotifyButton', ((rights & 16384) != 0) && (browserfullscreen == false) && (currentNode.agent) && (currentNode.agent.id < 5) && (inputAllowed) && (currentNode.agent) && online); QV('DeskNotifyButton', ((rights & 16384) != 0) && (browserfullscreen == false) && (currentNode.agent) && (currentNode.agent.id < 5) && (inputAllowed) && (currentNode.agent) && online);
@ -6526,6 +6525,21 @@
// Toggle mouse and keyboard input // Toggle mouse and keyboard input
function toggleKvmControl() { putstore('DeskControl', (Q('DeskControl').checked?1:0)); QS('DeskControlSpan').color = Q('DeskControl').checked?null:'red'; } function toggleKvmControl() { putstore('DeskControl', (Q('DeskControl').checked?1:0)); QS('DeskControlSpan').color = Q('DeskControl').checked?null:'red'; }
// Toggle desktop session recording
function deskRecordSession() {
if (desktop == null) return;
if (desktop.m.recordedData == null) {
// Start recording
console.log('Start record');
desktop.m.StartRecording();
} else {
// Stop recording
console.log('Stop record');
var rec = desktop.m.StopRecording();
console.log('frames', rec.length);
}
}
// Save the desktop image to file // Save the desktop image to file
function deskSaveImage() { function deskSaveImage() {
if (xxdialogMode || desktop == null || desktop.State != 3) return; if (xxdialogMode || desktop == null || desktop.State != 3) return;
@ -7672,7 +7686,7 @@
// Storage // Storage
if (hardware.identifiers && ident.storage_devices) { if (hardware.identifiers && ident.storage_devices) {
var x = ''; var x = '';
// Sort Memory // Sort Storage
ident.storage_devices.sort(function(a, b) { if (a.Caption > b.Caption) return 1; if (a.Caption < b.Caption) return -1; return 0; }); ident.storage_devices.sort(function(a, b) { if (a.Caption > b.Caption) return 1; if (a.Caption < b.Caption) return -1; return 0; });
x += '<table style=width:100%>'; x += '<table style=width:100%>';