diff --git a/meshcentral-config-schema.json b/meshcentral-config-schema.json index fe5263b8..0d9d5ed7 100644 --- a/meshcentral-config-schema.json +++ b/meshcentral-config-schema.json @@ -677,10 +677,11 @@ "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 }, - "maxRecordings": { "type": "integer" }, - "maxRecordingSizeMegabytes": { "type": "integer" }, + "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." }, + "maxRecordings": { "type": "integer", "default": null, "description": "Maximum number of recording files to keep." }, + "maxRecordingDays": { "type": "integer", "default": null, "description": "Maximum number of days to keep a recording." }, + "maxRecordingSizeMegabytes": { "type": "integer", "default": null, "description": "Maximum number of recordings in megabytes. Once exceed, remove the oldest recordings." }, "protocols": { "type": "array", "uniqueItems": true, "items": { "type": "integer" }, "description": "This is an array: 1 = Terminal, 2 = Desktop, 5 = Files, 100 = Intel AMT WSMAN, 101 = Intel AMT Redirection, 200 = Messenger" } }, "required": [ "protocols" ] diff --git a/meshdesktopmultiplex.js b/meshdesktopmultiplex.js index 5766e1eb..5723bec1 100644 --- a/meshdesktopmultiplex.js +++ b/meshdesktopmultiplex.js @@ -827,10 +827,10 @@ function CreateDesktopMultiplexor(parent, domain, nodeid, func) { // If there is a recording quota, remove any old recordings if needed function cleanUpRecordings() { - if ((parent.cleanUpRecordingsActive !== true) && domain.sessionrecording && ((typeof domain.sessionrecording.maxrecordings == 'number') || (typeof domain.sessionrecording.maxrecordingsizemegabytes == 'number'))) { + if ((parent.cleanUpRecordingsActive !== true) && domain.sessionrecording && ((typeof domain.sessionrecording.maxrecordings == 'number') || (typeof domain.sessionrecording.maxrecordingsizemegabytes == 'number') || (typeof domain.sessionrecording.maxrecordingdays == 'number'))) { parent.cleanUpRecordingsActive = true; setTimeout(function () { - var recPath = null, fs = require('fs'); + var recPath = null, fs = require('fs'), now = Date.now(); if (domain.sessionrecording.filepath) { recPath = domain.sessionrecording.filepath; } else { recPath = parent.parent.recordpath; } fs.readdir(recPath, function (err, files) { if ((err != null) || (files == null)) { delete parent.cleanUpRecordingsActive; return; } @@ -838,22 +838,27 @@ function CreateDesktopMultiplexor(parent, domain, nodeid, func) { for (var i in files) { if (files[i].endsWith('.mcrec')) { var j = files[i].indexOf('-'); - if (j > 0) { recfiles.push({ n: files[i], r: files[i].substring(j + 1), s: fs.statSync(parent.parent.path.join(recPath, files[i])).size }); } + if (j > 0) { + var stats = null; + try { stats = fs.statSync(parent.parent.path.join(recPath, files[i])); } catch (ex) { } + if (stats != null) { recfiles.push({ n: files[i], r: files[i].substring(j + 1), s: stats.size, t: stats.mtimeMs }); } + } } } recfiles.sort(function (a, b) { if (a.r < b.r) return 1; if (a.r > b.r) return -1; return 0; }); var totalFiles = 0, totalSize = 0; for (var i in recfiles) { var overQuota = false; - if ((typeof domain.sessionrecording.maxrecordings == 'number') && (totalFiles >= domain.sessionrecording.maxrecordings)) { overQuota = true; } - else if ((typeof domain.sessionrecording.maxrecordingsizemegabytes == 'number') && (totalSize >= (domain.sessionrecording.maxrecordingsizemegabytes * 1048576))) { overQuota = true; } + if ((typeof domain.sessionrecording.maxrecordings == 'number') && (domain.sessionrecording.maxrecordings > 0) && (totalFiles >= domain.sessionrecording.maxrecordings)) { overQuota = true; } + else if ((typeof domain.sessionrecording.maxrecordingsizemegabytes == 'number') && (domain.sessionrecording.maxrecordingsizemegabytes > 0) && (totalSize >= (domain.sessionrecording.maxrecordingsizemegabytes * 1048576))) { overQuota = true; } + else if ((typeof domain.sessionrecording.maxrecordingdays == 'number') && (domain.sessionrecording.maxrecordingdays > 0) && (((now - recfiles[i].t) / 1000 / 60 / 60 / 24) >= domain.sessionrecording.maxrecordingdays)) { overQuota = true; } if (overQuota) { fs.unlinkSync(parent.parent.path.join(recPath, recfiles[i].n)); } totalFiles++; totalSize += recfiles[i].s; } delete parent.cleanUpRecordingsActive; }); - }); + }, 500); } } diff --git a/meshrelay.js b/meshrelay.js index 54c36e7a..9fa7de71 100644 --- a/meshrelay.js +++ b/meshrelay.js @@ -935,10 +935,10 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) { // If there is a recording quota, remove any old recordings if needed function cleanUpRecordings() { - if ((parent.cleanUpRecordingsActive !== true) && domain.sessionrecording && ((typeof domain.sessionrecording.maxrecordings == 'number') || (typeof domain.sessionrecording.maxrecordingsizemegabytes == 'number'))) { + if ((parent.cleanUpRecordingsActive !== true) && domain.sessionrecording && ((typeof domain.sessionrecording.maxrecordings == 'number') || (typeof domain.sessionrecording.maxrecordingsizemegabytes == 'number') || (typeof domain.sessionrecording.maxrecordingdays == 'number'))) { parent.cleanUpRecordingsActive = true; setTimeout(function () { - var recPath = null, fs = require('fs'); + var recPath = null, fs = require('fs'), now = Date.now(); if (domain.sessionrecording.filepath) { recPath = domain.sessionrecording.filepath; } else { recPath = parent.parent.recordpath; } fs.readdir(recPath, function (err, files) { if ((err != null) || (files == null)) { delete parent.cleanUpRecordingsActive; return; } @@ -947,9 +947,9 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) { if (files[i].endsWith('.mcrec')) { var j = files[i].indexOf('-'); if (j > 0) { - var size = null; - try { size = fs.statSync(parent.parent.path.join(recPath, files[i])).size } catch (ex) { } - if (size != null) { recfiles.push({ n: files[i], r: files[i].substring(j + 1), s: size }); } + var stats = null; + try { stats = fs.statSync(parent.parent.path.join(recPath, files[i])); } catch (ex) { } + if (stats != null) { recfiles.push({ n: files[i], r: files[i].substring(j + 1), s: stats.size, t: stats.mtimeMs }); } } } } @@ -957,8 +957,9 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) { var totalFiles = 0, totalSize = 0; for (var i in recfiles) { var overQuota = false; - if ((typeof domain.sessionrecording.maxrecordings == 'number') && (totalFiles >= domain.sessionrecording.maxrecordings)) { overQuota = true; } - else if ((typeof domain.sessionrecording.maxrecordingsizemegabytes == 'number') && (totalSize >= (domain.sessionrecording.maxrecordingsizemegabytes * 1048576))) { overQuota = true; } + if ((typeof domain.sessionrecording.maxrecordings == 'number') && (domain.sessionrecording.maxrecordings > 0) && (totalFiles >= domain.sessionrecording.maxrecordings)) { overQuota = true; } + else if ((typeof domain.sessionrecording.maxrecordingsizemegabytes == 'number') && (domain.sessionrecording.maxrecordingsizemegabytes > 0) && (totalSize >= (domain.sessionrecording.maxrecordingsizemegabytes * 1048576))) { overQuota = true; } + else if ((typeof domain.sessionrecording.maxrecordingdays == 'number') && (domain.sessionrecording.maxrecordingdays > 0) && (((now - recfiles[i].t) / 1000 / 60 / 60 / 24) >= domain.sessionrecording.maxrecordingdays)) { overQuota = true; } if (overQuota) { fs.unlinkSync(parent.parent.path.join(recPath, recfiles[i].n)); } totalFiles++; totalSize += recfiles[i].s;