diff --git a/meshcentral-config-schema.json b/meshcentral-config-schema.json
index 005f3075..fe5263b8 100644
--- a/meshcentral-config-schema.json
+++ b/meshcentral-config-schema.json
@@ -675,6 +675,7 @@
"type": "object",
"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." },
"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" },
"index": { "type": "boolean", "default": false },
diff --git a/meshdesktopmultiplex.js b/meshdesktopmultiplex.js
index b9b2add7..209b9656 100644
--- a/meshdesktopmultiplex.js
+++ b/meshdesktopmultiplex.js
@@ -731,9 +731,21 @@ function CreateDesktopMultiplexor(parent, domain, nodeid, func) {
if ((domain.sessionrecording == true || ((typeof domain.sessionrecording == 'object') && ((domain.sessionrecording.protocols == null) || (domain.sessionrecording.protocols.indexOf(2) >= 0))))) {
// Check again to make sure we need to start recording
- if (domain.sessionrecording.onlyselecteddevicegroups === true) {
- var mesh = parent.meshes[obj.meshid];
- if ((mesh.flags == null) || ((mesh.flags & 4) == 0)) { func(false); return; } // Do not record the session
+ if ((domain.sessionrecording.onlyselecteddevicegroups === true) || (domain.sessionrecording.onlyselectedusers === true)) {
+ var record = false;
+
+ // Check user recording
+ if (domain.sessionrecording.onlyselectedusers === true) {
+ // TODO: Check recording ???
+ }
+
+ // Check device group recording
+ if (domain.sessionrecording.onlyselecteddevicegroups === true) {
+ var mesh = parent.meshes[obj.meshid];
+ if ((mesh.flags != null) && ((mesh.flags & 4) != 0)) { record = true; }
+ }
+
+ if (record == false) { func(false); return; } // Do not record the session
}
var now = new Date(Date.now());
diff --git a/meshrelay.js b/meshrelay.js
index 367ef99d..21affb31 100644
--- a/meshrelay.js
+++ b/meshrelay.js
@@ -349,31 +349,41 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) {
xtextSession = 2; // 1 = Raw recording of all strings, 2 = Record chat session messages only.
}
if ((obj.req.query.p != null) && (obj.req.query.nodeid != null) && (sessionUser != null) && (domain.sessionrecording == true || ((typeof domain.sessionrecording == 'object') && ((domain.sessionrecording.protocols == null) || (domain.sessionrecording.protocols.indexOf(parseInt(obj.req.query.p)) >= 0))))) { recordSession = true; }
-
+
if (recordSession) {
// Get the computer name
parent.db.Get(obj.req.query.nodeid, function (err, nodes) {
- var xusername = '', xdevicename = '', xdevicename2 = null, node = null;
+ var xusername = '', xdevicename = '', xdevicename2 = null, node = null, record = true;
if ((nodes != null) && (nodes.length == 1)) { node = nodes[0]; xdevicename2 = node.name; xdevicename = '-' + parent.common.makeFilename(node.name); }
- // Check again if we need to do recording
- if ((node == null) || (domain.sessionrecording.onlyselecteddevicegroups === true)) {
- var mesh = null;
- if (node != null) { mesh = parent.meshes[node.meshid]; }
- if ((node == null) || (mesh == null) || (mesh.flags == null) || ((mesh.flags & 4) == 0)) {
- // Do not record the session, just send session start
- try { ws.send('c'); } catch (ex) { } // Send connect to both peers
- try { relayinfo.peer1.ws.send('c'); } catch (ex) { }
+ // Check again if we need to do messenger recording
+ if ((domain.sessionrecording.onlyselectedusers === true) || (domain.sessionrecording.onlyselecteddevicegroups === true)) {
+ record = false;
- // Send any stored push messages
- obj.pushStoredMessages();
- relayinfo.peer1.pushStoredMessages();
-
- // Send other peer's image
- obj.sendPeerImage();
- relayinfo.peer1.sendPeerImage();
- return;
+ // Check if this device group needs to be recorded
+ if ((node == null) || (domain.sessionrecording.onlyselecteddevicegroups === true)) {
+ var mesh = null;
+ if (node != null) { mesh = parent.meshes[node.meshid]; }
+ if ((node != null) && (mesh != null) && (mesh.flags != null) && ((mesh.flags & 4) != 0)) { record = true; }
}
+
+ // Check if this user needs to be recorded
+ if ((sessionUser != null) && (sessionUser.flags != null) && ((sessionUser.flags & 2) != 0)) { record = true; }
+ }
+
+ // Do not record the session, just send session start
+ if (record == false) {
+ try { ws.send('c'); } catch (ex) { } // Send connect to both peers
+ try { relayinfo.peer1.ws.send('c'); } catch (ex) { }
+
+ // Send any stored push messages
+ obj.pushStoredMessages();
+ relayinfo.peer1.pushStoredMessages();
+
+ // Send other peer's image
+ obj.sendPeerImage();
+ relayinfo.peer1.sendPeerImage();
+ return;
}
// Get the username and make it acceptable as a filename
diff --git a/meshuser.js b/meshuser.js
index 26221cab..eac7d0ea 100644
--- a/meshuser.js
+++ b/meshuser.js
@@ -492,7 +492,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
serverinfo.languages = parent.renderLanguages;
serverinfo.tlshash = Buffer.from(parent.webCertificateFullHashs[domain.id], 'binary').toString('hex').toUpperCase(); // SHA384 of server HTTPS certificate
serverinfo.agentCertHash = parent.agentCertificateHashBase64;
- if ((domain.sessionrecording) && (domain.sessionrecording.onlyselecteddevicegroups === true)) { serverinfo.devGroupSessionRecording = 1; } // Allow enabling of session recording
+ if ((domain.sessionrecording) && (domain.sessionrecording.onlyselectedusers === true)) { serverinfo.usersSessionRecording = 1; } // Allow enabling of session recording for user groups
+ if ((domain.sessionrecording) && (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)) {
var matchingDomains = [];
for (var i in parent.parent.config.domains[domain.id].amtacmactivation.acmmatch) {
@@ -1581,6 +1582,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
if (command.resetNextLogin === true) { chguser.passchange = -1; }
if ((command.consent != null) && (typeof command.consent == 'number')) { if (command.consent == 0) { delete chguser.consent; } else { chguser.consent = command.consent; } change = 1; }
if ((command.phone != null) && (typeof command.phone == 'string') && ((command.phone == '') || isPhoneNumber(command.phone))) { if (command.phone == '') { delete chguser.phone; } else { chguser.phone = command.phone; } change = 1; }
+ if ((command.flags != null) && (typeof command.flags == 'number')) { if (command.flags == 0) { delete chguser.flags; } else { chguser.flags = command.flags; } change = 1; } // Flags: 1 = Account Image, 2 = Session Recording
// Site admins can change any server rights, user managers can only change AccountLock, NoMeshCmd and NoNewGroups
if (common.validateInt(command.siteadmin) && (chguser._id !== user._id) && (chguser.siteadmin != command.siteadmin)) { // We can't change our own siteadmin permissions.
diff --git a/sample-config-advanced.json b/sample-config-advanced.json
index d4fdd321..71d31283 100644
--- a/sample-config-advanced.json
+++ b/sample-config-advanced.json
@@ -311,6 +311,7 @@
},
"_agentConfig": [ "webSocketMaskOverride=1", "coreDumpEnabled=1" ],
"_sessionRecording": {
+ "_onlySelectedUsers": true,
"_onlySelectedDeviceGroups": true,
"_filepath": "C:\\temp",
"_index": true,
diff --git a/views/default.handlebars b/views/default.handlebars
index 4aebcef6..4a70b8ad 100644
--- a/views/default.handlebars
+++ b/views/default.handlebars
@@ -14051,6 +14051,17 @@
x += addDeviceAttribute("Phone Number", (user.phone?user.phone:('' + "None" + '')) + ' ');
}
+ // Display features
+ if (serverinfo.usersSessionRecording == 1) {
+ var userFeatures = [];
+ if (user.flags) {
+ if ((serverinfo.usersSessionRecording == 1) && (user.flags & 2)) { userFeatures.push("Record Sessions"); }
+ }
+ userFeatures = userFeatures.join(', ');
+ if (userFeatures == '') { userFeatures = '' + "None" + ''; }
+ x += addDeviceAttribute("Features", addLink(userFeatures, 'p20edituserfeatures()'));
+ }
+
x += addDeviceAttribute("Server Rights", premsg + msg.join(', ') + '
');
if (user.quota) x += addDeviceAttribute("Server Quota", EscapeHtml(parseInt(user.quota) / 1024) + ' k');
x += addDeviceAttribute("Creation", printDateTime(new Date(user.creation * 1000)));
@@ -14165,6 +14176,24 @@
p30editPhoneValidate();
}
+ function p20edituserfeatures() {
+ if (xxdialogMode) return;
+ var flags = (currentUser.flags)?currentUser.flags:0, x = ''; // Flags: 1 = Account Image, 2 = Session Recording
+ if (serverinfo.usersSessionRecording == 1) {
+ x += '