Added device notes support

This commit is contained in:
Ylian Saint-Hilaire 2018-04-12 18:14:03 -07:00
parent bcb7100ced
commit 4080abd217
14 changed files with 114 additions and 18 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -817,7 +817,9 @@ function createMeshCore(agent) {
this.websocket.rtcchannel.on('end', function () { /*sendConsoleText('Tunnel #' + this.websocket.tunnel.index + ' WebRTC data channel closed');*/ });
this.websocket.write("{\"ctrlChannel\":\"102938\",\"type\":\"webrtc0\"}"); // Indicate we are ready for WebRTC switch-over.
});
ws.write({ type: 'answer', ctrlChannel: '102938', sdp: ws.webrtc.setOffer(obj.sdp) });
var sdp = null;
try { sdp = ws.webrtc.setOffer(obj.sdp); } catch (ex) { }
if (sdp != null) { ws.write({ type: 'answer', ctrlChannel: '102938', sdp: sdp }); }
}
}

1
db.js
View File

@ -92,6 +92,7 @@ module.exports.CreateDB = function (args, datapath) {
obj.GetUserWithEmail = function (domain, email, func) { obj.file.find({ type: 'user', domain: domain, email: email }, { type: 0 }, func); }
obj.GetUserWithVerifiedEmail = function (domain, email, func) { obj.file.find({ type: 'user', domain: domain, email: email, emailVerified: true }, { type: 0 }, func); }
obj.Remove = function (id) { obj.file.remove({ _id: id }); }
obj.RemoveNode = function (id) { obj.file.remove({ node: id }, { multi: true }); }
obj.RemoveAll = function (func) { obj.file.remove({}, { multi: true }, func); }
obj.RemoveAllOfType = function (type, func) { obj.file.remove({ type: type }, { multi: true }, func); }
obj.InsertMany = function (data, func) { obj.file.insert(data, func); }

View File

@ -95,6 +95,9 @@ module.exports.CreateLetsEncrypt = function (parent) {
agreeTos: true,
rsaKeySize: rsaKeySize,
challengeType: 'http-01'
//renewWithin: 15 * 24 * 60 * 60 * 1000 // 15 days
//renewWithin: 81 * 24 * 60 * 60 * 1000, // 81 days
//renewBy: 80 * 24 * 60 * 60 * 1000 // 80 days
}).then(function (xresults) {
obj.parent.performServerCertUpdate(); // Reset the server, TODO: Reset all peers
}, function (err) {

View File

@ -50,8 +50,10 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
if (obj.agentUpdate != null) { obj.fs.close(obj.agentUpdate.fd); obj.agentUpdate = null; }
if (obj.agentInfo.capabilities & 0x20) { // This is a temporary agent, remote it
// Delete this node including network interface information and events
obj.db.Remove(obj.dbNodeKey);
obj.db.Remove('if' + obj.dbNodeKey);
obj.db.Remove(obj.dbNodeKey); // Remove node with that id
obj.db.Remove('if' + obj.dbNodeKey); // Remove interface information
obj.db.Remove('nt' + obj.dbNodeKey); // Remove notes
obj.db.RemoveNode(obj.dbNodeKey); // Remove all entries with node:id
// Event node deletion
obj.parent.parent.DispatchEvent(['*', obj.dbMeshKey], obj, { etype: 'node', action: 'removenode', nodeid: obj.dbNodeKey, domain: obj.domain.id, nolog: 1 })
@ -276,8 +278,13 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
obj.db.Set(device);
// Event the new node
if (obj.agentInfo.capabilities & 0x20) {
// This is a temporary agent, don't log.
obj.parent.parent.DispatchEvent(['*', obj.dbMeshKey], obj, { etype: 'node', action: 'addnode', node: device, domain: domain.id, nolog: 1 })
} else {
var change = 'Added device ' + obj.agentInfo.computerName + ' to mesh ' + mesh.name;
obj.parent.parent.DispatchEvent(['*', obj.dbMeshKey], obj, { etype: 'node', action: 'addnode', node: device, msg: change, domain: domain.id })
}
} else {
// Device already exists, look if changes has occured
device = nodes[0];
@ -292,6 +299,9 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
if (change == 1) {
obj.db.Set(device);
// If this is a temporary device, don't log changes
if (obj.agentInfo.capabilities & 0x20) { log = 0; }
// Event the node change
var event = { etype: 'node', action: 'changenode', nodeid: obj.dbNodeKey, domain: domain.id };
if (log == 0) { event.nolog = 1; } else { event.msg = 'Changed device ' + device.name + ' from mesh ' + mesh.name + ': ' + changes.join(', '); }
@ -581,6 +591,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
// Event the node change
var event = { etype: 'node', action: 'changenode', nodeid: obj.dbNodeKey, domain: domain.id, msg: 'Changed device ' + device.name + ' from mesh ' + mesh.name + ': ' + changes.join(', ') };
if (obj.agentInfo.capabilities & 0x20) { event.nolog = 1; } // If this is a temporary device, don't log changes
var device2 = obj.common.Clone(device);
if (device2.intelamt && device2.intelamt.pass) delete device2.intelamt.pass; // Remove the Intel AMT password before eventing this.
event.node = device;
@ -616,6 +627,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
// Event the node change
var event = { etype: 'node', action: 'changenode', nodeid: obj.dbNodeKey, domain: domain.id, msg: 'Changed device ' + device.name + ' from mesh ' + mesh.name + ': ' + changes.join(', ') };
if (obj.agentInfo.capabilities & 0x20) { event.nolog = 1; } // If this is a temporary device, don't log changes
var device2 = obj.common.Clone(device);
if (device2.intelamt && device2.intelamt.pass) delete device2.intelamt.pass; // Remove the Intel AMT password before eventing this.
event.node = device;

View File

@ -713,9 +713,11 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
// Check if this user has rights to do this
if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 4) == 0)) return;
// Delete this node including network interface information and events
obj.db.Remove(node._id);
obj.db.Remove('if' + node._id);
// Delete this node including network interface information, events and timeline
obj.db.Remove(node._id); // Remove node with that id
obj.db.Remove('if' + node._id); // Remove interface information
obj.db.Remove('nt' + node._id); // Remove notes
obj.db.RemoveNode(node._id); // Remove all entries with node:id
// Event node deletion
var change = 'Removed device ' + node.name + ' from mesh ' + mesh.name;
@ -994,6 +996,54 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
}
break;
}
case 'setNotes':
{
// Argument validation
if (obj.common.validateString(command.nodeid, 1, 1024) == false) break; // Check nodeid
if ((command.nodeid.split('/').length != 3) || (command.nodeid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
// Check if this user has rights on this nodeid to set notes
obj.db.Get(command.nodeid, function (err, nodes) { // TODO: Make a NodeRights(user) method that also does not do a db call if agent is connected (???)
if (nodes.length == 1) {
var meshlinks = user.links[nodes[0].meshid];
if ((meshlinks) && (meshlinks.rights) && (meshlinks.rights & obj.parent.MESHRIGHT_SETNOTES != 0)) {
// Set the node's notes
if (obj.common.validateString(command.notes, 1) == false) {
obj.db.Remove('nt' + command.nodeid); // Delete the note for this node
} else {
obj.db.Set({ _id: 'nt' + command.nodeid, value: command.notes }); // Set the note for this node
}
}
}
});
break;
}
case 'getNotes':
{
// Argument validation
if (obj.common.validateString(command.nodeid, 1, 1024) == false) break; // Check nodeid
if ((command.nodeid.split('/').length != 3) || (command.nodeid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
// Get the device
obj.db.Get(command.nodeid, function (err, nodes) {
if (nodes.length != 1) { ws.send(JSON.stringify({ action: 'getnetworkinfo', nodeid: command.nodeid, netif: null })); return; }
var node = nodes[0];
// Get the mesh for this device
var mesh = obj.parent.meshes[node.meshid];
if (mesh) {
// Check if this user has rights to do this
if (mesh.links[user._id] == null || (mesh.links[user._id].rights == 0)) { return; }
// Get the notes about this node
obj.db.Get('nt' + command.nodeid, function (err, notes) {
if (notes.length != 1) { ws.send(JSON.stringify({ action: 'getNotes', nodeid: command.nodeid, notes: null })); return; }
ws.send(JSON.stringify({ action: 'getNotes', nodeid: command.nodeid, notes: notes[0].value }));
});
}
});
break;
}
}
});

View File

@ -1,6 +1,6 @@
{
"name": "meshcentral",
"version": "0.1.6-d",
"version": "0.1.6-f",
"keywords": [
"Remote Management",
"Intel AMT",

View File

@ -1051,6 +1051,20 @@
}
break;
}
case 'getNotes':{
var n = Q('d2devNotes');
if (n && (message.nodeid == n.attributes['nodeid'].value)) {
if (message.notes) { QH('d2devNotes', decodeURIComponent(message.notes)); } else { QH('d2devNotes', ''); }
var ro = n.attributes['ro'].value == 'true';
if (ro == false) { // If we have permissions, set read/write on this note.
n.removeAttribute('readonly');
QE('idx_dlgOkButton', true);
QV('idx_dlgOkButton', true);
focusTextBox('d2devNotes');
}
}
break;
}
case 'event': {
if (!message.event.nolog) {
events.unshift(message.event);
@ -2761,9 +2775,10 @@
x += addDeviceAttribute('Connectivity', cstate.join(', '));
}
x += '</table>';
x += '</table><br />';
// Show action button, only show if we have permissions 4, 8, 64
if ((meshrights & 76) != 0) { x += '<br /><input type=button value=Actions title="Perform power actions on the device" onclick=deviceActionFunction() />'; }
if ((meshrights & 76) != 0) { x += '<input type=button value=Actions title="Perform power actions on the device" onclick=deviceActionFunction() />'; }
x += '<input type=button value=Notes title="View notes about this device" onclick=deviceNotesFunction(' + ((meshrights & 128) == 0) + ',"' + node._id + '") />';
QH('p10html', x);
// Show node last 7 days timeline
@ -2844,6 +2859,14 @@
go(panel);
}
function deviceNotesFunction(readonly, nodeid) {
if (xxdialogMode) return;
setDialogMode(2, "Device Notes", 2, deviceNotesFunctionEx, '<textarea id=d2devNotes ro=' + readonly + ' nodeid=' + nodeid + ' readonly style=width:100%;height:200px;resize:none;overflow-y:scroll></textarea>', nodeid);
meshserver.send({ action: 'getNotes', nodeid: nodeid });
}
function deviceNotesFunctionEx(buttons, tag) { meshserver.send({ action: 'setNotes', nodeid: tag, notes: encodeURIComponent(Q('d2devNotes').value) }); }
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 />";
@ -4485,6 +4508,7 @@
x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20meshagentconsole>Mesh Agent Console<br>';
x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20meshserverfiles>Server Files<br>';
x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20wakedevices>Wake Devices<br>';
x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20editnotes>Edit Notes<br>';
x += '</div>';
setDialogMode(2, "Add User to Mesh", 3, p20showAddMeshUserDialogEx, x);
p20validateAddMeshUserDialog();
@ -4502,6 +4526,7 @@
QE('p20meshagentconsole', !Q('p20fulladmin').checked);
QE('p20meshserverfiles', !Q('p20fulladmin').checked);
QE('p20wakedevices', !Q('p20fulladmin').checked);
QE('p20editnotes', !Q('p20fulladmin').checked);
}
function p20showAddMeshUserDialogEx() {
@ -4514,6 +4539,7 @@
if (Q('p20meshagentconsole').checked == true) meshadmin += 16;
if (Q('p20meshserverfiles').checked == true) meshadmin += 32;
if (Q('p20wakedevices').checked == true) meshadmin += 64;
if (Q('p20editnotes').checked == true) meshadmin += 128;
}
meshserver.send({ action: 'addmeshuser', meshid: currentMesh._id, meshname: currentMesh.name, username: Q('dp20username').value , meshadmin: meshadmin});
}
@ -4531,6 +4557,7 @@
if ((meshrights & 16) != 0) r += ', Agent Console';
if ((meshrights & 32) != 0) r += ', Server Files';
if ((meshrights & 64) != 0) r += ', Wake Devices';
if ((meshrights & 128) != 0) r += ', Edit Notes';
}
r = r.substring(2);
if (r == '') { r = 'No Rights'; }

View File

@ -80,6 +80,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
const MESHRIGHT_AGENTCONSOLE = 16;
const MESHRIGHT_SERVERFILES = 32;
const MESHRIGHT_WAKEDEVICE = 64;
const MESHRIGHT_SETNOTES = 128;
// Site rights
const SITERIGHT_SERVERBACKUP = 1;