mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2025-02-12 11:01:52 +00:00
Added MeshAgent power actions
This commit is contained in:
parent
1473b091b0
commit
d8464ddd44
10 changed files with 124 additions and 37 deletions
Binary file not shown.
Binary file not shown.
|
@ -46,8 +46,13 @@ function createMeshCore(agent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get our location (lat/long) using our public IP address
|
// Get our location (lat/long) using our public IP address
|
||||||
|
var getIpLocationDataExInProgress = false;
|
||||||
|
var getIpLocationDataExCounts = [ 0, 0 ];
|
||||||
function getIpLocationDataEx(func) {
|
function getIpLocationDataEx(func) {
|
||||||
|
if (getIpLocationDataExInProgress == true) { return false; }
|
||||||
try {
|
try {
|
||||||
|
getIpLocationDataExInProgress = true;
|
||||||
|
getIpLocationDataExCounts[0]++;
|
||||||
http.request({
|
http.request({
|
||||||
host: 'ipinfo.io', // TODO: Use a HTTP proxy if needed!!!!
|
host: 'ipinfo.io', // TODO: Use a HTTP proxy if needed!!!!
|
||||||
port: 80,
|
port: 80,
|
||||||
|
@ -60,11 +65,13 @@ function createMeshCore(agent) {
|
||||||
resp.end = function () {
|
resp.end = function () {
|
||||||
var location = null;
|
var location = null;
|
||||||
try { if (typeof geoData == 'string') { var result = JSON.parse(geoData); if (result.ip && result.loc) { location = result; } } } catch (e) { }
|
try { if (typeof geoData == 'string') { var result = JSON.parse(geoData); if (result.ip && result.loc) { location = result; } } } catch (e) { }
|
||||||
if (func) { func(location); }
|
if (func) { getIpLocationDataExCounts[1]++; func(location); }
|
||||||
}
|
}
|
||||||
|
getIpLocationDataExInProgress = false;
|
||||||
}).end();
|
}).end();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
catch (e) { }
|
catch (e) { return false; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove all Gateway MAC addresses for interface list. This is useful because the gateway MAC is not always populated reliably.
|
// Remove all Gateway MAC addresses for interface list. This is useful because the gateway MAC is not always populated reliably.
|
||||||
|
@ -247,6 +254,18 @@ function createMeshCore(agent) {
|
||||||
// TODO!!!!
|
// TODO!!!!
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'poweraction': {
|
||||||
|
// Server telling us to execute a power action
|
||||||
|
if ((mesh.ExecPowerState != undefined) && (data.actiontype)) {
|
||||||
|
var forced = 0;
|
||||||
|
if (data.forced == 1) { forced = 1; }
|
||||||
|
data.actiontype = parseInt(data.actiontype);
|
||||||
|
sendConsoleText('Performing power action=' + data.actiontype + ', forced=' + forced + '.');
|
||||||
|
var r = mesh.ExecPowerState(data.actiontype, forced);
|
||||||
|
sendConsoleText('ExecPowerState returned code: ' + r);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 'location': {
|
case 'location': {
|
||||||
// Update the location information of this node
|
// Update the location information of this node
|
||||||
getIpLocationData(function (location) { mesh.SendCommand({ "action": "location", "type": "publicip", "value": location }); });
|
getIpLocationData(function (location) { mesh.SendCommand({ "action": "location", "type": "publicip", "value": location }); });
|
||||||
|
@ -520,7 +539,7 @@ function createMeshCore(agent) {
|
||||||
var response = null;
|
var response = null;
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case 'help': { // Displays available commands
|
case 'help': { // Displays available commands
|
||||||
response = 'Available commands: help, info, args, print, type, dbget, dbset, dbcompact, parseurl, httpget, wsconnect, wssend, wsclose, notify, ls, amt, netinfo, location.';
|
response = 'Available commands: help, info, args, print, type, dbget, dbset, dbcompact, parseurl, httpget, wsconnect, wssend, wsclose, notify, ls, amt, netinfo, location, power.';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'notify': { // Send a notification message to the mesh
|
case 'notify': { // Send a notification message to the mesh
|
||||||
|
@ -727,8 +746,21 @@ function createMeshCore(agent) {
|
||||||
sendConsoleText(args['_'].join(' '));
|
sendConsoleText(args['_'].join(' '));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'location': {
|
case 'location': { // Get location information about this computer
|
||||||
getIpLocationData(function (location) { sendConsoleText("Public IP location:\r\n" + objToString(location, 0, '.'), sessionid); }, args['_'][0]);
|
getIpLocationData(function (location) { sendConsoleText('IpLocation: ' + getIpLocationDataExCounts[0] + ' querie(s), ' + getIpLocationDataExCounts[1] + ' response(s), inProgress: ' + getIpLocationDataExInProgress + "\r\nPublic IP location data:\r\n" + objToString(location, 0, '.'), sessionid); }, args['_'][0]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'power': { // Execute a power action on this computer
|
||||||
|
if (mesh.ExecPowerState == undefined) {
|
||||||
|
response = 'Power command not supported on this agent.';
|
||||||
|
} else {
|
||||||
|
if ((args['_'].length == 0) || (typeof args['_'][0] != 'number')) {
|
||||||
|
response = 'Proper usage: power (actionNumber), where actionNumber is:\r\n LOGOFF = 1\r\n SHUTDOWN = 2\r\n REBOOT = 3\r\n SLEEP = 4\r\n HIBERNATE = 5\r\n DISPLAYON = 6\r\n KEEPAWAKE = 7\r\n BEEP = 8\r\n CTRLALTDEL = 9\r\n VIBRATE = 13\r\n FLASH = 14'; // Display correct command usage
|
||||||
|
} else {
|
||||||
|
var r = mesh.ExecPowerState(args['_'][0], args['_'][1]);
|
||||||
|
response = 'Power action executed with return code: ' + r + '.';
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: { // This is an unknown command, return an error message
|
default: { // This is an unknown command, return an error message
|
||||||
|
|
22
meshagent.js
22
meshagent.js
|
@ -26,14 +26,16 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||||
obj.agentInfo;
|
obj.agentInfo;
|
||||||
obj.agentUpdate = null;
|
obj.agentUpdate = null;
|
||||||
var agentUpdateBlockSize = 65520;
|
var agentUpdateBlockSize = 65520;
|
||||||
|
obj.remoteaddr = obj.ws._socket.remoteAddress;
|
||||||
|
if (obj.remoteaddr.startsWith('::ffff:')) { obj.remoteaddr = obj.remoteaddr.substring(7); }
|
||||||
|
|
||||||
// Send a message to the mesh agent
|
// Send a message to the mesh agent
|
||||||
obj.send = function (data) { if (typeof data == 'string') { obj.ws.send(new Buffer(data, 'binary')); } else { obj.ws.send(data); } }
|
obj.send = function (data) { if (typeof data == 'string') { obj.ws.send(new Buffer(data, 'binary')); } else { obj.ws.send(data); } }
|
||||||
|
|
||||||
// Disconnect this agent
|
// Disconnect this agent
|
||||||
obj.close = function (arg) {
|
obj.close = function (arg) {
|
||||||
if ((arg == 1) || (arg == null)) { try { obj.ws.close(); obj.parent.parent.debug(1, 'Soft disconnect ' + obj.nodeid); } catch (e) { console.log(e); } } // Soft close, close the websocket
|
if ((arg == 1) || (arg == null)) { try { obj.ws.close(); obj.parent.parent.debug(1, 'Soft disconnect ' + obj.nodeid + ' (' + obj.remoteaddr + ')'); } catch (e) { console.log(e); } } // Soft close, close the websocket
|
||||||
if (arg == 2) { try { obj.ws._socket._parent.end(); obj.parent.parent.debug(1, 'Hard disconnect ' + obj.nodeid); } catch (e) { console.log(e); } } // Hard close, close the TCP socket
|
if (arg == 2) { try { obj.ws._socket._parent.end(); obj.parent.parent.debug(1, 'Hard disconnect ' + obj.nodeid + ' (' + obj.remoteaddr + ')'); } catch (e) { console.log(e); } } // Hard close, close the TCP socket
|
||||||
if (obj.parent.wsagents[obj.dbNodeKey] == obj) {
|
if (obj.parent.wsagents[obj.dbNodeKey] == obj) {
|
||||||
delete obj.parent.wsagents[obj.dbNodeKey];
|
delete obj.parent.wsagents[obj.dbNodeKey];
|
||||||
obj.parent.parent.ClearConnectivityState(obj.dbMeshKey, obj.dbNodeKey, 1);
|
obj.parent.parent.ClearConnectivityState(obj.dbMeshKey, obj.dbNodeKey, 1);
|
||||||
|
@ -211,7 +213,8 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||||
ws.on('error', function (err) { console.log(err); });
|
ws.on('error', function (err) { console.log(err); });
|
||||||
|
|
||||||
// If the mesh agent web socket is closed, clean up.
|
// If the mesh agent web socket is closed, clean up.
|
||||||
ws.on('close', function (req) { obj.close(0); });
|
ws.on('close', function (req) { obj.parent.parent.debug(1, 'Agent disconnect ' + obj.nodeid + ' (' + obj.remoteaddr + ')'); obj.close(0); });
|
||||||
|
// obj.ws._socket._parent.on('close', function (req) { obj.parent.parent.debug(1, 'Agent TCP disconnect ' + obj.nodeid + ' (' + obj.remoteaddr + ')'); });
|
||||||
|
|
||||||
// Start authenticate the mesh agent by sending a auth nonce & server TLS cert hash.
|
// Start authenticate the mesh agent by sending a auth nonce & server TLS cert hash.
|
||||||
// Send 256 bits SHA256 hash of TLS cert public key + 256 bits nonce
|
// Send 256 bits SHA256 hash of TLS cert public key + 256 bits nonce
|
||||||
|
@ -223,9 +226,9 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||||
if (obj.authenticated =! 1 || obj.meshid == null) return;
|
if (obj.authenticated =! 1 || obj.meshid == null) return;
|
||||||
// Check that the mesh exists
|
// Check that the mesh exists
|
||||||
obj.db.Get(obj.dbMeshKey, function (err, meshes) {
|
obj.db.Get(obj.dbMeshKey, function (err, meshes) {
|
||||||
if (meshes.length == 0) { console.log('Agent connected with invalid domain/mesh, holding connection.'); return; } // If we disconnect, the agnet will just reconnect. We need to log this or tell agent to connect in a few hours.
|
if (meshes.length == 0) { console.log('Agent connected with invalid domain/mesh, holding connection (' + obj.remoteaddr + ').'); return; } // If we disconnect, the agnet will just reconnect. We need to log this or tell agent to connect in a few hours.
|
||||||
var mesh = meshes[0];
|
var mesh = meshes[0];
|
||||||
if (mesh.mtype != 2) { console.log('Agent connected with invalid mesh type, holding connection.'); return; } // If we disconnect, the agnet will just reconnect. We need to log this or tell agent to connect in a few hours.
|
if (mesh.mtype != 2) { console.log('Agent connected with invalid mesh type, holding connection (' + obj.remoteaddr + ').'); return; } // If we disconnect, the agnet will just reconnect. We need to log this or tell agent to connect in a few hours.
|
||||||
|
|
||||||
// Check that the node exists
|
// Check that the node exists
|
||||||
obj.db.Get(obj.dbNodeKey, function (err, nodes) {
|
obj.db.Get(obj.dbNodeKey, function (err, nodes) {
|
||||||
|
@ -269,6 +272,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||||
obj.parent.wsagents[obj.dbNodeKey] = obj;
|
obj.parent.wsagents[obj.dbNodeKey] = obj;
|
||||||
if (dupAgent) {
|
if (dupAgent) {
|
||||||
// Close the duplicate agent
|
// Close the duplicate agent
|
||||||
|
obj.parent.parent.debug(1, 'Duplicate agent ' + obj.nodeid + ' (' + obj.remoteaddr + ')');
|
||||||
dupAgent.close();
|
dupAgent.close();
|
||||||
} else {
|
} else {
|
||||||
// Indicate the agent is connected
|
// Indicate the agent is connected
|
||||||
|
@ -306,7 +310,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||||
delete obj.agentnonce;
|
delete obj.agentnonce;
|
||||||
delete obj.unauth;
|
delete obj.unauth;
|
||||||
if (obj.unauthsign) delete obj.unauthsign;
|
if (obj.unauthsign) delete obj.unauthsign;
|
||||||
obj.parent.parent.debug(1, 'Verified agent connection to ' + obj.nodeid);
|
obj.parent.parent.debug(1, 'Verified agent connection to ' + obj.nodeid + ' (' + obj.remoteaddr + ').');
|
||||||
obj.authenticated = 1;
|
obj.authenticated = 1;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -315,7 +319,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||||
function processAgentData(msg) {
|
function processAgentData(msg) {
|
||||||
var str = msg.toString('utf8');
|
var str = msg.toString('utf8');
|
||||||
if (str[0] == '{') {
|
if (str[0] == '{') {
|
||||||
try { command = JSON.parse(str) } catch (e) { console.log('Unable to parse JSON'); return; } // If the command can't be parsed, ignore it.
|
try { command = JSON.parse(str) } catch (e) { console.log('Unable to parse JSON (' + obj.remoteaddr + ').'); return; } // If the command can't be parsed, ignore it.
|
||||||
switch (command.action) {
|
switch (command.action) {
|
||||||
case 'msg':
|
case 'msg':
|
||||||
{
|
{
|
||||||
|
@ -434,9 +438,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||||
if (device.intelamt.host != command.intelamt.host) { device.intelamt.host = command.intelamt.host; change = 1; changes.push('AMT host'); }
|
if (device.intelamt.host != command.intelamt.host) { device.intelamt.host = command.intelamt.host; change = 1; changes.push('AMT host'); }
|
||||||
}
|
}
|
||||||
if (mesh.mtype == 2) {
|
if (mesh.mtype == 2) {
|
||||||
var remoteaddr = obj.ws._socket.remoteAddress;
|
if (device.host != obj.remoteaddr) { device.host = obj.remoteaddr; change = 1; changes.push('host'); }
|
||||||
if (remoteaddr.startsWith('::ffff:')) { remoteaddr = remoteaddr.substring(7); }
|
|
||||||
if (device.host != remoteaddr) { device.host = remoteaddr; change = 1; changes.push('host'); }
|
|
||||||
// TODO: Check that the agent has an interface that is the same as the one we got this websocket connection on. Only set if we have a match.
|
// TODO: Check that the agent has an interface that is the same as the one we got this websocket connection on. Only set if we have a match.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
25
meshrelay.js
25
meshrelay.js
|
@ -17,9 +17,11 @@ module.exports.CreateMeshRelay = function (parent, ws, req) {
|
||||||
var obj = {};
|
var obj = {};
|
||||||
obj.ws = ws;
|
obj.ws = ws;
|
||||||
obj.peer = null;
|
obj.peer = null;
|
||||||
|
obj.parent = parent;
|
||||||
obj.id = req.query['id'];
|
obj.id = req.query['id'];
|
||||||
|
obj.remoteaddr = obj.ws._socket.remoteAddress;
|
||||||
|
if (obj.remoteaddr.startsWith('::ffff:')) { obj.remoteaddr = obj.remoteaddr.substring(7); }
|
||||||
|
|
||||||
//console.log('Got relay connection for: ' + obj.id);
|
|
||||||
if (obj.id == undefined) { obj.ws.close(); obj.id = null; return null; } // Attempt to connect without id, drop this.
|
if (obj.id == undefined) { obj.ws.close(); obj.id = null; return null; } // Attempt to connect without id, drop this.
|
||||||
|
|
||||||
// Validate that the id is valid, we only need to do this on non-authenticated sessions.
|
// Validate that the id is valid, we only need to do this on non-authenticated sessions.
|
||||||
|
@ -51,15 +53,18 @@ module.exports.CreateMeshRelay = function (parent, ws, req) {
|
||||||
relayinfo.peer1.ws.peer = relayinfo.peer2.ws;
|
relayinfo.peer1.ws.peer = relayinfo.peer2.ws;
|
||||||
relayinfo.peer2.ws.peer = relayinfo.peer1.ws;
|
relayinfo.peer2.ws.peer = relayinfo.peer1.ws;
|
||||||
|
|
||||||
|
obj.parent.parent.debug(1, 'Relay connected: ' + obj.id + ' (' + obj.remoteaddr + ' --> ' + obj.peer.remoteaddr + ')');
|
||||||
} else {
|
} else {
|
||||||
// Connected already, drop (TODO: maybe we should re-connect?)
|
// Connected already, drop (TODO: maybe we should re-connect?)
|
||||||
obj.id = null;
|
obj.id = null;
|
||||||
obj.ws.close();
|
obj.ws.close();
|
||||||
|
obj.parent.parent.debug(1, 'Relay duplicate: ' + obj.id + ' (' + obj.remoteaddr + ')');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Setup the connection, wait for peer
|
// Setup the connection, wait for peer
|
||||||
parent.wsrelays[obj.id] = { peer1 : obj, state : 1 };
|
parent.wsrelays[obj.id] = { peer1: obj, state: 1 };
|
||||||
|
obj.parent.parent.debug(1, 'Relay holding: ' + obj.id + ' (' + obj.remoteaddr + ')');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,24 +73,26 @@ module.exports.CreateMeshRelay = function (parent, ws, req) {
|
||||||
};
|
};
|
||||||
|
|
||||||
// When data is received from the mesh relay web socket
|
// When data is received from the mesh relay web socket
|
||||||
ws.on('message', function (data)
|
ws.on('message', function (data) {
|
||||||
{
|
if (this.peer != null) { try { this.pause(); this.peer.send(data, ws.flushSink); } catch (e) { } }
|
||||||
if (this.peer != null) { try { this.pause(); this.peer.send(data, ws.flushSink); } catch (e) { } }
|
});
|
||||||
});
|
|
||||||
|
|
||||||
// If error, do nothing
|
// If error, do nothing
|
||||||
ws.on('error', function (err) { console.log(err); });
|
ws.on('error', function (err) { console.log(err); });
|
||||||
|
|
||||||
// If the mesh relay web socket is closed
|
// If the mesh relay web socket is closed
|
||||||
ws.on('close', function (req) {
|
ws.on('close', function (req) {
|
||||||
//console.log('Got relay disconnection for: ' + obj.id);
|
|
||||||
if (obj.id != null) {
|
if (obj.id != null) {
|
||||||
var relayinfo = parent.wsrelays[obj.id];
|
var relayinfo = parent.wsrelays[obj.id];
|
||||||
if (relayinfo.state == 2) {
|
if (relayinfo.state == 2) {
|
||||||
// Disconnect the peer
|
// Disconnect the peer
|
||||||
var peer = (relayinfo.peer1 == obj)?relayinfo.peer2:relayinfo.peer1;
|
var peer = (relayinfo.peer1 == obj) ? relayinfo.peer2 : relayinfo.peer1;
|
||||||
|
obj.parent.parent.debug(1, 'Relay disconnect: ' + obj.id + ' (' + obj.remoteaddr + ' --> ' + peer.remoteaddr + ')');
|
||||||
peer.id = null;
|
peer.id = null;
|
||||||
peer.ws._socket.end();
|
try { peer.ws.close(); } catch (e) { } // Soft disconnect
|
||||||
|
try { peer.ws._socket._parent.end(); } catch (e) { } // Hard disconnect
|
||||||
|
} else {
|
||||||
|
obj.parent.parent.debug(1, 'Relay disconnect: ' + obj.id + ' (' + obj.remoteaddr + ')');
|
||||||
}
|
}
|
||||||
delete parent.wsrelays[obj.id];
|
delete parent.wsrelays[obj.id];
|
||||||
obj.peer = null;
|
obj.peer = null;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "meshcentral",
|
"name": "meshcentral",
|
||||||
"version": "0.0.6-v",
|
"version": "0.0.6-x",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"Remote Management",
|
"Remote Management",
|
||||||
"Intel AMT",
|
"Intel AMT",
|
||||||
|
|
|
@ -30,6 +30,7 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
|
||||||
obj.socket = new WebSocket(url);
|
obj.socket = new WebSocket(url);
|
||||||
obj.socket.onopen = obj.xxOnSocketConnected;
|
obj.socket.onopen = obj.xxOnSocketConnected;
|
||||||
obj.socket.onmessage = obj.xxOnMessage;
|
obj.socket.onmessage = obj.xxOnMessage;
|
||||||
|
obj.socket.onerror = function (e) { console.error(e); }
|
||||||
obj.socket.onclose = obj.xxOnSocketClosed;
|
obj.socket.onclose = obj.xxOnSocketClosed;
|
||||||
obj.xxStateChange(1);
|
obj.xxStateChange(1);
|
||||||
obj.meshserver.Send({ action: 'msg', type: 'tunnel', nodeid: obj.nodeid, value: url2 });
|
obj.meshserver.Send({ action: 'msg', type: 'tunnel', nodeid: obj.nodeid, value: url2 });
|
||||||
|
|
|
@ -1535,25 +1535,29 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function groupActionFunction() {
|
function groupActionFunction() {
|
||||||
var x = "Select an operation to perform on all selected devices.<br /><br />";
|
var x = "Select an operation to perform on all selected devices. Actions will be performed only with proper rights.<br /><br />";
|
||||||
x += addHtmlValue('Operation', '<select id=d2groupop style=float:right;width:250px><option value=1>Wake-up devices</option><option value=2>Delete devices</option></select>');
|
x += addHtmlValue('Operation', '<select id=d2groupop style=float:right;width:250px><option value=100>Wake-up devices</option><option value=4>Sleep devices</option><option value=3>Reset devices</option><option value=2>Power off devices</option><option value=101>Delete devices</option></select>');
|
||||||
setDialogMode(2, "Group Action", 3, groupActionFunctionEx, x);
|
setDialogMode(2, "Group Action", 3, groupActionFunctionEx, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
function groupActionFunctionEx() {
|
function groupActionFunctionEx() {
|
||||||
var op = Q('d2groupop').value;
|
var op = Q('d2groupop').value;
|
||||||
if (op == 1) {
|
if (op == 100) {
|
||||||
// Group wake
|
// Group wake
|
||||||
var nodeids = [], elements = document.getElementsByClassName("DeviceCheckbox"), checkcount = 0;
|
var nodeids = [], elements = document.getElementsByClassName("DeviceCheckbox"), checkcount = 0;
|
||||||
for (var i in elements) { if (elements[i].checked) { nodeids.push(elements[i].value.substring(6)); } }
|
for (var i in elements) { if (elements[i].checked) { nodeids.push(elements[i].value.substring(6)); } }
|
||||||
meshserver.Send({ action: 'wakedevices', nodeids: nodeids });
|
meshserver.Send({ action: 'wakedevices', nodeids: nodeids });
|
||||||
}
|
} else if (op == 101) {
|
||||||
if (op == 2) {
|
|
||||||
// Group delete, ask for confirmation
|
// Group delete, ask for confirmation
|
||||||
var x = "Confirm delete selected devices(s)?<br /><br />";
|
var x = "Confirm delete selected devices(s)?<br /><br />";
|
||||||
x += "<input id=d2check type=checkbox onchange=d2groupActionFunctionDelEx() />Confirm";
|
x += "<input id=d2check type=checkbox onchange=d2groupActionFunctionDelEx() />Confirm";
|
||||||
setDialogMode(2, "Delete Nodes", 3, groupActionFunctionDelEx, x);
|
setDialogMode(2, "Delete Nodes", 3, groupActionFunctionDelEx, x);
|
||||||
QE('idx_dlgOkButton', false);
|
QE('idx_dlgOkButton', false);
|
||||||
|
} else {
|
||||||
|
// Power operation
|
||||||
|
var nodeids = [], elements = document.getElementsByClassName("DeviceCheckbox"), checkcount = 0;
|
||||||
|
for (var i in elements) { if (elements[i].checked) { nodeids.push(elements[i].value.substring(6)); } }
|
||||||
|
meshserver.Send({ action: 'poweraction', nodeids: nodeids, actiontype: op });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2463,9 +2467,9 @@
|
||||||
Q('p14iframe').contentWindow.setAuthCallback(updateAmtCredentials);
|
Q('p14iframe').contentWindow.setAuthCallback(updateAmtCredentials);
|
||||||
|
|
||||||
// Display "action" button on desktop/terminal/files
|
// Display "action" button on desktop/terminal/files
|
||||||
QV('deskActionsBtn', (meshrights & 76) != 0);
|
QV('deskActionsBtn', (meshrights & 72) != 0); // 72 = Wake-up + Remote Control permissions
|
||||||
QV('termActionsBtn', (meshrights & 76) != 0);
|
QV('termActionsBtn', (meshrights & 72) != 0);
|
||||||
QV('filesActionsBtn', (meshrights & 76) != 0);
|
QV('filesActionsBtn', (meshrights & 72) != 0);
|
||||||
|
|
||||||
// Request the power timeline
|
// Request the power timeline
|
||||||
if ((powerTimelineNode != currentNode._id) && (powerTimelineReq != currentNode._id)) { powerTimelineReq = currentNode._id; meshserver.Send({ action: 'powertimeline', nodeid: currentNode._id }); }
|
if ((powerTimelineNode != currentNode._id) && (powerTimelineReq != currentNode._id)) { powerTimelineReq = currentNode._id; meshserver.Send({ action: 'powertimeline', nodeid: currentNode._id }); }
|
||||||
|
@ -2475,16 +2479,24 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function deviceActionFunction() {
|
function deviceActionFunction() {
|
||||||
|
var meshrights = meshes[currentNode.meshid].links['user/{{{domain}}}/' + userinfo.name.toLowerCase()].rights;
|
||||||
var x = "Select an operation to perform on this device.<br /><br />";
|
var x = "Select an operation to perform on this device.<br /><br />";
|
||||||
x += addHtmlValue('Operation', '<select id=d2deviceop style=float:right;width:250px><option value=1>Wake-up</option></select>');
|
var y = '<select id=d2deviceop style=float:right;width:250px>';
|
||||||
|
if ((meshrights & 64) != 0) { y += '<option value=100>Wake-up</option>'; } // Wake-up permission
|
||||||
|
if ((meshrights & 8) != 0) { y += '<option value=4>Sleep</option><option value=3>Reset</option><option value=2>Power off</option>'; } // Remote control permission
|
||||||
|
y += '</select>';
|
||||||
|
x += addHtmlValue('Operation', y);
|
||||||
setDialogMode(2, "Device Action", 3, deviceActionFunctionEx, x);
|
setDialogMode(2, "Device Action", 3, deviceActionFunctionEx, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
function deviceActionFunctionEx() {
|
function deviceActionFunctionEx() {
|
||||||
var op = Q('d2deviceop').value;
|
var op = Q('d2deviceop').value;
|
||||||
if (op == 1) {
|
if (op == 100) {
|
||||||
// Device wake
|
// Device wake
|
||||||
meshserver.Send({ action: 'wakedevices', nodeids: [ currentNode._id ] });
|
meshserver.Send({ action: 'wakedevices', nodeids: [ currentNode._id ] });
|
||||||
|
} else {
|
||||||
|
// Power operation
|
||||||
|
meshserver.Send({ action: 'poweraction', nodeids: [ currentNode._id ], actiontype: op });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -146,8 +146,6 @@
|
||||||
else if (passStrength >= 60) { QH('passWarning', '<span style=color:blue><b>Good Password</b><span>'); }
|
else if (passStrength >= 60) { QH('passWarning', '<span style=color:blue><b>Good Password</b><span>'); }
|
||||||
else { QH('passWarning', '<span style=color:red><b>Weak Password</b><span>'); }
|
else { QH('passWarning', '<span style=color:red><b>Weak Password</b><span>'); }
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(passStrength);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return a password strength score
|
// Return a password strength score
|
||||||
|
|
35
webserver.js
35
webserver.js
|
@ -1391,6 +1391,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
}
|
}
|
||||||
case 'wakedevices':
|
case 'wakedevices':
|
||||||
{
|
{
|
||||||
|
// TODO: INPUT VALIDATION!!!
|
||||||
// TODO: We can optimize this a lot.
|
// TODO: We can optimize this a lot.
|
||||||
// - We should get a full list of all MAC's to wake first.
|
// - We should get a full list of all MAC's to wake first.
|
||||||
// - We should try to only have one agent per subnet (using Gateway MAC) send a wake-on-lan.
|
// - We should try to only have one agent per subnet (using Gateway MAC) send a wake-on-lan.
|
||||||
|
@ -1443,6 +1444,40 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
ws.send(JSON.stringify({ action: 'wakedevices' }));
|
ws.send(JSON.stringify({ action: 'wakedevices' }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'poweraction':
|
||||||
|
{
|
||||||
|
// TODO: INPUT VALIDATION!!!
|
||||||
|
for (var i in command.nodeids) {
|
||||||
|
var nodeid = command.nodeids[i], powerActions = 0;
|
||||||
|
if ((nodeid.split('/').length == 3) && (nodeid.split('/')[1] == domain.id)) { // Validate the domain, operation only valid for current domain
|
||||||
|
// Get the device
|
||||||
|
obj.db.Get(nodeid, function (err, nodes) {
|
||||||
|
if (nodes.length != 1) return;
|
||||||
|
var node = nodes[0];
|
||||||
|
|
||||||
|
// Get the mesh for this device
|
||||||
|
var mesh = obj.meshes[node.meshid];
|
||||||
|
if (mesh) {
|
||||||
|
|
||||||
|
// Check if this user has rights to do this
|
||||||
|
if (mesh.links[user._id] != undefined && ((mesh.links[user._id].rights & 8) != 0)) { // "Remote Control permission"
|
||||||
|
|
||||||
|
// Get this device
|
||||||
|
var agent = obj.wsagents[node._id];
|
||||||
|
if (agent != null) {
|
||||||
|
// Send the power command
|
||||||
|
agent.send(JSON.stringify({ action: 'poweraction', actiontype: command.actiontype }));
|
||||||
|
powerActions++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Confirm we may be doing something (TODO)
|
||||||
|
ws.send(JSON.stringify({ action: 'poweraction' }));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'getnetworkinfo':
|
case 'getnetworkinfo':
|
||||||
|
|
Loading…
Reference in a new issue