mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2025-02-12 11:01:52 +00:00
Added device notes support
This commit is contained in:
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.
|
@ -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
1
db.js
|
@ -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); }
|
||||
|
|
|
@ -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) {
|
||||
|
|
16
meshagent.js
16
meshagent.js
|
@ -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;
|
||||
|
|
56
meshuser.js
56
meshuser.js
|
@ -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;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "meshcentral",
|
||||
"version": "0.1.6-d",
|
||||
"version": "0.1.6-f",
|
||||
"keywords": [
|
||||
"Remote Management",
|
||||
"Intel AMT",
|
||||
|
|
|
@ -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'; }
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue