MQTT improvements, multi-line toast fix.

This commit is contained in:
Ylian Saint-Hilaire 2019-10-09 15:56:27 -07:00
parent a79233e825
commit 7baf812c47
9 changed files with 105 additions and 162 deletions

View File

@ -798,6 +798,7 @@ function createMeshCore(agent)
// Display a toast message
if (data.title && data.msg) {
MeshServerLog('Displaying toast message, title=' + data.title + ', message=' + data.msg, data);
data.msg = data.msg.split('\r').join('\\r').split('\n').join('\\n');
try { require('toaster').Toast(data.title, data.msg); } catch (ex) { }
}
break;
@ -1139,7 +1140,7 @@ function createMeshCore(agent)
// User Consent Prompt is required
// Send a console message back using the console channel, "\n" is supported.
this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: 'Waiting for user to grant access...' }));
var pr = require('message-box').create('MeshCentral', this.httprequest.username + ' requesting Terminal Access. Grant access?', 10);
var pr = require('message-box').create('MeshCentral', this.httprequest.username + ' requesting Terminal Access. Grant access?', 30);
pr.ws = this;
this.pause();
@ -1229,7 +1230,7 @@ function createMeshCore(agent)
// User Consent Prompt is required
// Send a console message back using the console channel, "\n" is supported.
this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: 'Waiting for user to grant access...' }));
var pr = require('message-box').create('MeshCentral', this.httprequest.username + ' requesting KVM Access. Grant access?', 10);
var pr = require('message-box').create('MeshCentral', this.httprequest.username + ' requesting KVM Access. Grant access?', 30);
pr.ws = this;
this.pause();
@ -1287,7 +1288,7 @@ function createMeshCore(agent)
// User Consent Prompt is required
// Send a console message back using the console channel, "\n" is supported.
this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: 'Waiting for user to grant access...' }));
var pr = require('message-box').create('MeshCentral', this.httprequest.username + ' requesting remote file access. Grant access?', 10);
var pr = require('message-box').create('MeshCentral', this.httprequest.username + ' requesting remote file access. Grant access?', 30);
pr.ws = this;
this.pause();
@ -1788,8 +1789,7 @@ function createMeshCore(agent)
break;
}
case 'toast': {
if (args['_'].length < 1) { response = 'Proper usage: toast "message"'; } else
{
if (args['_'].length < 1) { response = 'Proper usage: toast "message"'; } else {
require('toaster').Toast('MeshCentral', args['_'][0]).then(sendConsoleText, sendConsoleText);
}
break;

View File

@ -798,6 +798,7 @@ function createMeshCore(agent)
// Display a toast message
if (data.title && data.msg) {
MeshServerLog('Displaying toast message, title=' + data.title + ', message=' + data.msg, data);
data.msg = data.msg.split('\r').join('\\r').split('\n').join('\\n');
try { require('toaster').Toast(data.title, data.msg); } catch (ex) { }
}
break;
@ -1139,7 +1140,7 @@ function createMeshCore(agent)
// User Consent Prompt is required
// Send a console message back using the console channel, "\n" is supported.
this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: 'Waiting for user to grant access...' }));
var pr = require('message-box').create('MeshCentral', this.httprequest.username + ' requesting Terminal Access. Grant access?', 10);
var pr = require('message-box').create('MeshCentral', this.httprequest.username + ' requesting Terminal Access. Grant access?', 30);
pr.ws = this;
this.pause();
@ -1229,7 +1230,7 @@ function createMeshCore(agent)
// User Consent Prompt is required
// Send a console message back using the console channel, "\n" is supported.
this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: 'Waiting for user to grant access...' }));
var pr = require('message-box').create('MeshCentral', this.httprequest.username + ' requesting KVM Access. Grant access?', 10);
var pr = require('message-box').create('MeshCentral', this.httprequest.username + ' requesting KVM Access. Grant access?', 30);
pr.ws = this;
this.pause();
@ -1287,7 +1288,7 @@ function createMeshCore(agent)
// User Consent Prompt is required
// Send a console message back using the console channel, "\n" is supported.
this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: 'Waiting for user to grant access...' }));
var pr = require('message-box').create('MeshCentral', this.httprequest.username + ' requesting remote file access. Grant access?', 10);
var pr = require('message-box').create('MeshCentral', this.httprequest.username + ' requesting remote file access. Grant access?', 30);
pr.ws = this;
this.pause();
@ -1788,8 +1789,7 @@ function createMeshCore(agent)
break;
}
case 'toast': {
if (args['_'].length < 1) { response = 'Proper usage: toast "message"'; } else
{
if (args['_'].length < 1) { response = 'Proper usage: toast "message"'; } else {
require('toaster').Toast('MeshCentral', args['_'][0]).then(sendConsoleText, sendConsoleText);
}
break;

View File

@ -1064,76 +1064,8 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
switch (command.action) {
case 'msg':
{
// Route a message.
// If this command has a sessionid, that is the target.
if (command.sessionid != null) {
if (typeof command.sessionid != 'string') break;
var splitsessionid = command.sessionid.split('/');
// Check that we are in the same domain and the user has rights over this node.
if ((splitsessionid[0] == 'user') && (splitsessionid[1] == domain.id)) {
// Check if this user has rights to get this message
//if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 16) == 0)) return; // TODO!!!!!!!!!!!!!!!!!!!!!
// See if the session is connected. If so, go ahead and send this message to the target node
var ws = parent.wssessions2[command.sessionid];
if (ws != null) {
command.nodeid = obj.dbNodeKey; // Set the nodeid, required for responses.
delete command.sessionid; // Remove the sessionid, since we are sending to that sessionid, so it's implyed.
try { ws.send(JSON.stringify(command)); } catch (ex) { }
} else if (parent.parent.multiServer != null) {
// See if we can send this to a peer server
var serverid = parent.wsPeerSessions2[command.sessionid];
if (serverid != null) {
command.fromNodeid = obj.dbNodeKey;
parent.parent.multiServer.DispatchMessageSingleServer(command, serverid);
}
}
}
} else if (command.userid != null) { // If this command has a userid, that is the target.
if (typeof command.userid != 'string') break;
var splituserid = command.userid.split('/');
// Check that we are in the same domain and the user has rights over this node.
if ((splituserid[0] == 'user') && (splituserid[1] == domain.id)) {
// Check if this user has rights to get this message
//if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 16) == 0)) return; // TODO!!!!!!!!!!!!!!!!!!!!!
// See if the session is connected
var sessions = parent.wssessions[command.userid];
// Go ahead and send this message to the target node
if (sessions != null) {
command.nodeid = obj.dbNodeKey; // Set the nodeid, required for responses.
delete command.userid; // Remove the userid, since we are sending to that userid, so it's implyed.
for (i in sessions) { sessions[i].send(JSON.stringify(command)); }
}
if (parent.parent.multiServer != null) {
// TODO: Add multi-server support
}
}
} else { // Route this command to the mesh
command.nodeid = obj.dbNodeKey;
var cmdstr = JSON.stringify(command);
for (var userid in parent.wssessions) { // Find all connected users for this mesh and send the message
var user = parent.users[userid];
if ((user != null) && (user.links != null)) {
var rights = user.links[obj.dbMeshKey];
if (rights != null) { // TODO: Look at what rights are needed for message routing
var xsessions = parent.wssessions[userid];
// Send the message to all users on this server
for (i in xsessions) { try { xsessions[i].send(cmdstr); } catch (e) { } }
}
}
}
// Send the message to all users of other servers
if (parent.parent.multiServer != null) {
delete command.nodeid;
command.fromNodeid = obj.dbNodeKey;
command.meshid = obj.dbMeshKey;
parent.parent.multiServer.DispatchMessage(command);
}
}
// Route a message
parent.routeAgentCommand(command, obj.domain.id, obj.dbNodeKey, obj.dbMeshKey);
break;
}
case 'coreinfo':

View File

@ -320,7 +320,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
var httpport = ((args.aliasport != null) ? args.aliasport : args.port);
// Build server information object
var serverinfo = { name: domain.dns ? domain.dns : parent.certificates.CommonName, mpsname: parent.certificates.AmtMpsName, mpsport: mpsport, mpspass: args.mpspass, port: httpport, emailcheck: ((parent.parent.mailserver != null) && (domain.auth != 'sspi') && (domain.auth != 'ldap') && (args.lanonly != true) && (parent.certificates.CommonName != null) && (parent.certificates.CommonName.indexOf('.') != -1)), domainauth: ((domain.auth == 'sspi') || (domain.auth == 'ldap')) };
var serverinfo = { name: domain.dns ? domain.dns : parent.certificates.CommonName, mpsname: parent.certificates.AmtMpsName, mpsport: mpsport, mpspass: args.mpspass, port: httpport, emailcheck: ((parent.parent.mailserver != null) && (domain.auth != 'sspi') && (domain.auth != 'ldap') && (args.lanonly != true) && (parent.certificates.CommonName != null) && (parent.certificates.CommonName.indexOf('.') != -1)), domainauth: ((domain.auth == 'sspi') || (domain.auth == 'ldap')), serverTime: Date.now() };
serverinfo.tlshash = Buffer.from(parent.webCertificateHashs[domain.id], 'binary').toString('hex').toUpperCase(); // SHA384 of server HTTPS certificate
if ((parent.parent.config.domains[domain.id].amtacmactivation != null) && (parent.parent.config.domains[domain.id].amtacmactivation.acmmatch != null)) {
var matchingDomains = [];
@ -2014,6 +2014,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
agentSession.sendUpdatedIntelAmtPolicy(); // Send the new Intel AMT policy
}
// If any MQTT sessions are connected on this server, switch it now.
if (parent.parent.mqttbroker != null) { parent.parent.mqttbroker.changeDeviceMesh(node._id, command.meshid); }
// Add the connection state
const state = parent.parent.GetConnectivityState(node._id);
if (state) {

View File

@ -58,6 +58,7 @@ module.exports.CreateMQTTBroker = function (parent, db, args) {
// Set the client nodeid and meshid
client.xdbNodeKey = 'node/' + xdomainid + '/' + xnodeid;
client.xdbMeshKey = 'mesh/' + xdomainid + '/' + xmeshid;
client.xdomainid = xdomainid;
// Check if this node exists in the database
db.Get(client.xdbNodeKey, function (err, nodes) {
@ -107,7 +108,7 @@ module.exports.CreateMQTTBroker = function (parent, db, args) {
aedes.authorizePublish = function (client, packet, callback) {
// Handle a published message
obj.parent.debug("mqtt", "AuthorizePublish, " + client.conn.xtransport + "://" + cleanRemoteAddr(client.conn.xip));
handleMessage(client.xdbNodeKey, client.xdbMeshKey, packet.topic, packet.payload);
handleMessage(client.xdbNodeKey, client.xdbMeshKey, client.xdomainid, packet.topic, packet.payload);
// We don't accept that any client message be published, so don't call the callback.
}
@ -128,9 +129,9 @@ module.exports.CreateMQTTBroker = function (parent, db, args) {
}
// Handle messages coming from clients
function handleMessage(nodeid, meshid, topic, message) {
function handleMessage(nodeid, meshid, domainid, topic, message) {
// Handle messages here
if (topic == 'console') { routeMessage({ action: 'msg', type: 'console', value: message.toString(), source: 'MQTT' }, nodeid, meshid); return; } // Handle console messages
if (topic == 'console') { parent.webserver.routeAgentCommand({ action: 'msg', type: 'console', value: message.toString(), source: 'MQTT' }, domainid, nodeid, meshid); return; } // Handle console messages
//console.log('handleMessage', nodeid, topic, message.toString());
//obj.publish(nodeid, 'echoTopic', "Echo: " + message.toString());
@ -139,78 +140,10 @@ module.exports.CreateMQTTBroker = function (parent, db, args) {
// Clean a IPv6 address that encodes a IPv4 address
function cleanRemoteAddr(addr) { if (typeof addr != 'string') { return null; } if (addr.indexOf('::ffff:') == 0) { return addr.substring(7); } else { return addr; } }
// Route a message
function routeMessage(command, dbNodeKey, dbMeshKey) {
// Route a message.
// If this command has a sessionid, that is the target.
if (command.sessionid != null) {
if (typeof command.sessionid != 'string') return;
var splitsessionid = command.sessionid.split('/');
// Check that we are in the same domain and the user has rights over this node.
if ((splitsessionid[0] == 'user') && (splitsessionid[1] == domain.id)) {
// Check if this user has rights to get this message
//if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 16) == 0)) return; // TODO!!!!!!!!!!!!!!!!!!!!!
// See if the session is connected. If so, go ahead and send this message to the target node
var ws = parent.webserver.wssessions2[command.sessionid];
if (ws != null) {
command.nodeid = dbNodeKey; // Set the nodeid, required for responses.
delete command.sessionid; // Remove the sessionid, since we are sending to that sessionid, so it's implyed.
try { ws.send(JSON.stringify(command)); } catch (ex) { }
} else if (parent.multiServer != null) {
// See if we can send this to a peer server
var serverid = parent.webserver.wsPeerSessions2[command.sessionid];
if (serverid != null) {
command.fromNodeid = dbNodeKey;
parent.multiServer.DispatchMessageSingleServer(command, serverid);
}
}
}
} else if (command.userid != null) { // If this command has a userid, that is the target.
if (typeof command.userid != 'string') return;
var splituserid = command.userid.split('/');
// Check that we are in the same domain and the user has rights over this node.
if ((splituserid[0] == 'user') && (splituserid[1] == domain.id)) {
// Check if this user has rights to get this message
//if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 16) == 0)) return; // TODO!!!!!!!!!!!!!!!!!!!!!
// See if the session is connected
var sessions = parent.webserver.wssessions[command.userid];
// Go ahead and send this message to the target node
if (sessions != null) {
command.nodeid = dbNodeKey; // Set the nodeid, required for responses.
delete command.userid; // Remove the userid, since we are sending to that userid, so it's implyed.
for (i in sessions) { sessions[i].send(JSON.stringify(command)); }
}
if (parent.multiServer != null) {
// TODO: Add multi-server support
}
}
} else { // Route this command to the mesh
command.nodeid = dbNodeKey;
var cmdstr = JSON.stringify(command);
for (var userid in parent.webserver.wssessions) { // Find all connected users for this mesh and send the message
var user = parent.webserver.users[userid];
if ((user != null) && (user.links != null)) {
var rights = user.links[dbMeshKey];
if (rights != null) { // TODO: Look at what rights are needed for message routing
var xsessions = parent.webserver.wssessions[userid];
// Send the message to all users on this server
for (i in xsessions) { try { xsessions[i].send(cmdstr); } catch (e) { } }
}
}
}
// Send the message to all users of other servers
if (parent.multiServer != null) {
delete command.nodeid;
command.fromNodeid = dbNodeKey;
command.meshid = dbMeshKey;
parent.multiServer.DispatchMessage(command);
}
}
// Change a node to a new meshid
obj.changeDeviceMesh = function(nodeid, newMeshId) {
var nodes = obj.connections[nodeid];
if (nodes != null) { for (var i in nodes) { nodes[i].xdbMeshKey = newMeshId; } }
}
return obj;

View File

@ -1,6 +1,6 @@
{
"name": "meshcentral",
"version": "0.4.1-x",
"version": "0.4.1-y",
"keywords": [
"Remote Management",
"Intel AMT",

File diff suppressed because one or more lines are too long

View File

@ -1447,6 +1447,7 @@
case 'serverinfo': {
serverinfo = message.serverinfo;
if (serverinfo.timeout) { setInterval(checkIdleSessionTimeout, 10000); checkIdleSessionTimeout(); }
if (debugmode == 1) { console.log("Server time: ", printDateTime(new Date(serverinfo.serverTime))); }
break;
}
case 'userinfo': {
@ -6476,7 +6477,7 @@
if ((consoleNode.conn & 16) != 0) { onlineText += ', MQTT is online' }
QH('p15statetext', onlineText);
QE('p15consoleText', online);
QE('p15uploadCore', online);
QE('p15uploadCore', ((consoleNode.conn & 1) != 0));
QV('p15outputselecttd', (consoleNode.conn & 17) == 17);
} else {
QH('p15statetext', 'Access Denied');
@ -6502,7 +6503,7 @@
var consoleHistory = [];
function p15consoleSend(e) {
if (e && e.keyCode != 13) return;
var v = Q('p15consoleText').value, t = '<div style=color:green>&gt; ' + v + '<br/></div>';
var v = Q('p15consoleText').value, t = '<div style=color:green>&gt; ' + EscapeHtml(v) + '<br/></div>';
if (xxcurrentView == 115) {
// Send the command to the server - TODO: In the future, we may support multiple servers.
@ -6539,7 +6540,7 @@
function p15consoleReceive(node, data, source) {
if (node === 'serverconsole') {
// Server console data
data = '<div>' + EscapeHtml(data) + '</div>'
data = '<div>' + data + '</div>'
consoleServerText += data;
if (consoleNode == 'server') {
Q('p15agentConsoleText').innerHTML += data;
@ -6547,7 +6548,7 @@
}
} else {
// Agent console data
if (source == 'MQTT') { data = '<div style=color:red>MQTT&gt; ' + EscapeHtml(data) + '<br/></div>'; } else { data = '<div>' + EscapeHtml(data) + '</div>' }
if (source == 'MQTT') { data = '<div style=color:red>MQTT&gt; ' + EscapeHtml(data) + '<br/></div>'; } else { data = '<div>' + data + '</div>' }
if (node.consoleText == null) { node.consoleText = data; } else { node.consoleText += data; }
if (consoleNode == node) {
Q('p15agentConsoleText').innerHTML += data;

View File

@ -3751,6 +3751,80 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
return null;
}
// Route a command from a agent. domainid, nodeid and meshid are the values of the source agent.
obj.routeAgentCommand = function (command, domainid, nodeid, meshid) {
// Route a message.
// If this command has a sessionid, that is the target.
if (command.sessionid != null) {
if (typeof command.sessionid != 'string') return;
var splitsessionid = command.sessionid.split('/');
// Check that we are in the same domain and the user has rights over this node.
if ((splitsessionid[0] == 'user') && (splitsessionid[1] == domainid)) {
// Check if this user has rights to get this message
//if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 16) == 0)) return; // TODO!!!!!!!!!!!!!!!!!!!!!
// See if the session is connected. If so, go ahead and send this message to the target node
var ws = obj.wssessions2[command.sessionid];
if (ws != null) {
command.nodeid = nodeid; // Set the nodeid, required for responses.
delete command.sessionid; // Remove the sessionid, since we are sending to that sessionid, so it's implyed.
try { ws.send(JSON.stringify(command)); } catch (ex) { }
} else if (parent.multiServer != null) {
// See if we can send this to a peer server
var serverid = obj.wsPeerSessions2[command.sessionid];
if (serverid != null) {
command.fromNodeid = nodeid;
parent.multiServer.DispatchMessageSingleServer(command, serverid);
}
}
}
} else if (command.userid != null) { // If this command has a userid, that is the target.
if (typeof command.userid != 'string') return;
var splituserid = command.userid.split('/');
// Check that we are in the same domain and the user has rights over this node.
if ((splituserid[0] == 'user') && (splituserid[1] == domainid)) {
// Check if this user has rights to get this message
//if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 16) == 0)) return; // TODO!!!!!!!!!!!!!!!!!!!!!
// See if the session is connected
var sessions = obj.wssessions[command.userid];
// Go ahead and send this message to the target node
if (sessions != null) {
command.nodeid = nodeid; // Set the nodeid, required for responses.
delete command.userid; // Remove the userid, since we are sending to that userid, so it's implyed.
for (i in sessions) { sessions[i].send(JSON.stringify(command)); }
}
if (parent.multiServer != null) {
// TODO: Add multi-server support
}
}
} else { // Route this command to the mesh
command.nodeid = nodeid;
var cmdstr = JSON.stringify(command);
for (var userid in obj.wssessions) { // Find all connected users for this mesh and send the message
var user = obj.users[userid];
if ((user != null) && (user.links != null)) {
var rights = user.links[meshid];
if (rights != null) { // TODO: Look at what rights are needed for message routing
var xsessions = obj.wssessions[userid];
// Send the message to all users on this server
for (i in xsessions) { try { xsessions[i].send(cmdstr); } catch (e) { } }
}
}
}
// Send the message to all users of other servers
if (parent.multiServer != null) {
delete command.nodeid;
command.fromNodeid = nodeid;
command.meshid = meshid;
parent.multiServer.DispatchMessage(command);
}
}
}
// Return true if a mobile browser is detected.
// This code comes from "http://detectmobilebrowsers.com/" and was modified, This is free and unencumbered software released into the public domain. For more information, please refer to the http://unlicense.org/
function isMobileBrowser(req) {