diff --git a/meshcentral-config-schema.json b/meshcentral-config-schema.json index a0efc9d43c..a07fbfc44f 100644 --- a/meshcentral-config-schema.json +++ b/meshcentral-config-schema.json @@ -677,6 +677,7 @@ "additionalProperties": false, "properties": { "onlySelectedUsers": { "type": "boolean", "default": false, "description": "When enabled, only device users with the session recording feature turned on will be recorded. When false, all users are recorded." }, + "onlySelectedUserGroups": { "type": "boolean", "default": false, "description": "When enabled, only device user groups with the session recording feature turned on will be recorded. When false, all users are recorded." }, "onlySelectedDeviceGroups": { "type": "boolean", "default": false, "description": "When enabled, only device groups with the session recording feature turned on will be recorded. When false, all devices are recorded." }, "filepath": { "type": "string", "description": "The file path where recording files are kept." }, "index": { "type": "boolean", "default": false, "description": "If true, automatically index remote desktop recordings so that the plays can skip to any place in the file." }, diff --git a/meshuser.js b/meshuser.js index fe0548c3e1..754905c385 100644 --- a/meshuser.js +++ b/meshuser.js @@ -505,7 +505,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use serverinfo.tlshash = Buffer.from(parent.webCertificateFullHashs[domain.id], 'binary').toString('hex').toUpperCase(); // SHA384 of server HTTPS certificate serverinfo.agentCertHash = parent.agentCertificateHashBase64; if (typeof domain.sessionrecording == 'object') { - if (domain.sessionrecording.onlyselectedusers === true) { serverinfo.usersSessionRecording = 1; } // Allow enabling of session recording for user groups + if (domain.sessionrecording.onlyselectedusers === true) { serverinfo.usersSessionRecording = 1; } // Allow enabling of session recording for users + if (domain.sessionrecording.onlyselectedusergroups === true) { serverinfo.userGroupsSessionRecording = 1; } // Allow enabling of session recording for user groups if (domain.sessionrecording.onlyselecteddevicegroups === true) { serverinfo.devGroupSessionRecording = 1; } // Allow enabling of session recording for device groups } if ((parent.parent.config.domains[domain.id].amtacmactivation != null) && (parent.parent.config.domains[domain.id].amtacmactivation.acmmatch != null)) { @@ -1937,14 +1938,22 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use if ((ugroupidsplit.length != 3) || (ugroupidsplit[0] != 'ugrp') || (ugroupidsplit[1] != domain.id)) break; // Get the user group + change = ''; var group = parent.userGroups[command.ugrpid]; if (group != null) { if ((common.validateString(command.name, 1, 64) == true) && (command.name != group.name)) { change = 'User group name changed from "' + group.name + '" to "' + command.name + '"'; group.name = command.name; } if ((common.validateString(command.desc, 0, 1024) == true) && (command.desc != group.desc)) { if (change != '') change += ' and description changed'; else change += 'User group "' + group.name + '" description changed'; group.desc = command.desc; } if ((typeof command.consent == 'number') && (command.consent != group.consent)) { if (change != '') change += ' and consent changed'; else change += 'User group "' + group.name + '" consent changed'; group.consent = command.consent; } + + if ((command.flags != null) && (typeof command.flags == 'number')) { + // Flags: 2 = Session Recording + if ((command.flags == 0) && (group.flags != null)) { delete group.flags; } else { if (command.flags !== group.flags) { group.flags = command.flags; } } + if (change == '') { change = 'User group flags changed.'; } + } + if (change != '') { db.Set(group); - var event = { etype: 'ugrp', userid: user._id, username: user.name, ugrpid: group._id, name: group.name, desc: group.desc, consent: ((group.consent == null) ? 0 : group.consent), action: 'usergroupchange', links: group.links, msg: change, domain: domain.id }; + var event = { etype: 'ugrp', userid: user._id, username: user.name, ugrpid: group._id, name: group.name, desc: group.desc, consent: ((group.consent == null) ? 0 : group.consent), action: 'usergroupchange', links: group.links, flags: group.flags, msg: change, domain: domain.id }; if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the mesh. Another event will come. parent.parent.DispatchEvent(['*', group._id, user._id], obj, event); } diff --git a/sample-config-advanced.json b/sample-config-advanced.json index 8f8bd3e6cc..0a0077a368 100644 --- a/sample-config-advanced.json +++ b/sample-config-advanced.json @@ -313,6 +313,7 @@ "_agentConfig": [ "webSocketMaskOverride=1", "coreDumpEnabled=1" ], "_sessionRecording": { "_onlySelectedUsers": true, + "_onlySelectedUserGroups": true, "_onlySelectedDeviceGroups": true, "_filepath": "C:\\temp", "_index": true, diff --git a/views/default-mobile.handlebars b/views/default-mobile.handlebars index ce35db7c8f..8c77713b9c 100644 --- a/views/default-mobile.handlebars +++ b/views/default-mobile.handlebars @@ -1743,6 +1743,7 @@ ugroup.name = message.event.name; ugroup.desc = message.event.desc; ugroup.links = message.event.links; + ugroup.flags = message.event.flags; } //mainUpdate(8192 + 16384); diff --git a/views/default.handlebars b/views/default.handlebars index 3c300b862c..cd929084b9 100644 --- a/views/default.handlebars +++ b/views/default.handlebars @@ -2935,6 +2935,7 @@ ugroup.name = message.event.name; if (message.event.desc) { ugroup.desc = message.event.desc; } else { delete ugroup.desc; } if (message.event.links) { ugroup.links = message.event.links; } else { delete ugroup.links; } + if (message.event.flags) { ugroup.flags = message.event.flags; } else { delete ugroup.flags; } if (typeof message.event.consent == 'number') { ugroup.consent = message.event.consent; } } mainUpdate(4096 + 8192 + 16384); @@ -12928,7 +12929,7 @@ var msg; if ((event.msgid == null) || (eventsMessageId[event.msgid] == null)) { - msg = EscapeHtml(event.msg).split('(R)').join('®'); + if (typeof event.msg == 'string') { msg = EscapeHtml(event.msg).split('(R)').join('®'); } else { msg = ''; } } else { msg = eventsMessageId[event.msgid]; if (event.msgArgs != null) { @@ -13828,6 +13829,15 @@ x += addDeviceAttribute("Description", desc); } + // Display features + if (serverinfo.userGroupsSessionRecording == 1) { + var userGroupFeatures = []; + if ((group.flags) && (group.flags & 2)) { userGroupFeatures.push("Record Sessions"); } + userGroupFeatures = userGroupFeatures.join(', '); + if (userGroupFeatures == '') { userGroupFeatures = '' + "None" + ''; } + x += addDeviceAttribute("Features", addLink(userGroupFeatures, 'p51edituserGroupFeatures()')); + } + // Display user consent flags for this user group { var consentOptionsStr = [], consent = 0; @@ -13951,6 +13961,23 @@ } } + function p51edituserGroupFeatures() { + if (xxdialogMode) return; + var flags = (currentUserGroup.flags)?currentUserGroup.flags:0, x = ''; // Flags: 2 = Session Recording + if (serverinfo.userGroupsSessionRecording == 1) { + x += '

'; + } + setDialogMode(2, "Edit User Group Features", 3, p51edituserGroupFeaturesEx, x); + } + + // Send to the server the new user's real name + function p51edituserGroupFeaturesEx() { + // Setup user flags + var f = 0; + if ((serverinfo.userGroupsSessionRecording == 1) && Q('d51flag1').checked) { f += 2; } + meshserver.send({ action: 'editusergroup', ugrpid: currentUserGroup._id, flags: f }); + } + function p51removeDeviceFromUserGroup(e, nodeid) { if (xxdialogMode) return; var node = getNodeFromId(decodeURIComponent(nodeid));