From a15a5e779da36c00f99714b2d4fd5646e2a53705 Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Wed, 8 Sep 2021 15:55:07 -0700 Subject: [PATCH] Started work on reports feature. --- db.js | 1 + meshuser.js | 62 ++++++++++++++ public/styles/style.css | 2 +- views/default.handlebars | 181 ++++++++++++++++++++++++++++++++++++++- 4 files changed, 242 insertions(+), 4 deletions(-) diff --git a/db.js b/db.js index 545df3d9..c44caf46 100644 --- a/db.js +++ b/db.js @@ -1402,6 +1402,7 @@ module.exports.CreateDB = function (parent, func) { obj.GetEventsWithLimit = function (ids, domain, limit, func) { obj.eventsfile.find({ domain: domain, ids: { $in: ids } }).project({ type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).limit(limit).toArray(func); }; obj.GetUserEvents = function (ids, domain, username, func) { obj.eventsfile.find({ domain: domain, $or: [{ ids: { $in: ids } }, { username: username }] }).project({ type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).toArray(func); }; obj.GetUserEventsWithLimit = function (ids, domain, username, limit, func) { obj.eventsfile.find({ domain: domain, $or: [{ ids: { $in: ids } }, { username: username }] }).project({ type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).limit(limit).toArray(func); }; + obj.GetEventsTimeRange = function (ids, domain, msgids, start, end, func) { obj.eventsfile.find({ domain: domain, $or: [{ ids: { $in: ids } }], msgid: { $in: msgids }, time: { $gte: start, $lte: end } }).project({ type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: 1 }).toArray(func); }; obj.GetUserLoginEvents = function (domain, userid, func) { obj.eventsfile.find({ domain: domain, action: { $in: ['authfail', 'login'] }, userid: userid, msgArgs: { $exists: true } }).project({ action: 1, time: 1, msgid: 1, msgArgs: 1, tokenName: 1 }).sort({ time: -1 }).toArray(func); }; obj.GetNodeEventsWithLimit = function (nodeid, domain, limit, func) { obj.eventsfile.find({ domain: domain, nodeid: nodeid }).project({ type: 0, etype: 0, _id: 0, domain: 0, ids: 0, node: 0, nodeid: 0 }).sort({ time: -1 }).limit(limit).toArray(func); }; obj.GetNodeEventsSelfWithLimit = function (nodeid, domain, userid, limit, func) { obj.eventsfile.find({ domain: domain, nodeid: nodeid, userid: { $in: [userid, null] } }).project({ type: 0, etype: 0, _id: 0, domain: 0, ids: 0, node: 0, nodeid: 0 }).sort({ time: -1 }).limit(limit).toArray(func); }; diff --git a/meshuser.js b/meshuser.js index 8849def8..105fca5a 100644 --- a/meshuser.js +++ b/meshuser.js @@ -5408,6 +5408,68 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use break; } + case 'report': { + // Report request. Validate the input + if (common.validateInt(command.type, 1, 1) == false) break; // Validate type + if (common.validateInt(command.groupBy, 1, 3) == false) break; // Validate groupBy: 1 = User, 2 = Device, 3 = Day + if ((typeof command.start != 'number') || (typeof command.end != 'number') || (command.start >= command.end)) break; // Validate start and end time + + if (command.type == 1) { // This is the remote session report. Shows desktop, terminal, files... + // If we are not user administrator on this site, only search for events with our own user id. + var ids = [user._id]; + if ((user.siteadmin & SITERIGHT_MANAGEUSERS) != 0) { ids = ['*']; } + + // Get the events in the time range + db.GetEventsTimeRange(ids, domain.id, [5, 10, 12], new Date(command.start * 1000), new Date(command.end * 1000), function (err, docs) { + if (err != null) return; + var data = { groups: {} }; + + // Columns + if (command.groupBy == 1) { + data.groupFormat = 'user'; + data.columns = [{ id: 'time', title: "time", format: 'datetime' }, { id: "nodeid", title: "device", format: "node" }, { id: "protocol", title: "session", format: "protocol", align: "center" }, { id: "length", title: "length", format: "seconds", align: "center" } ]; + } else if (command.groupBy == 2) { + data.groupFormat = 'node'; + data.columns = [{ id: 'time', title: "time", format: 'datetime' }, { id: "userid", title: "user", format: "user" }, { id: "protocol", title: "session", format: "protocol", align: "center" }, { id: "length", title: "length", format: "seconds", align: "center" } ]; + } else if (command.groupBy == 3) { + data.columns = [{ id: 'time', title: "time", format: 'time' }, { id: "nodeid", title: "device", format: "node" }, { id: "userid", title: "user", format: "user" }, { id: "protocol", title: "session", format: "protocol", align: "center" }, { id: "length", title: "length", format: "seconds", align:"center" } ]; + } + + // Rows + for (var i in docs) { + var entry = { time: docs[i].time.valueOf() }; + + // UserID + if (command.groupBy != 1) { entry.userid = docs[i].userid; } + if (command.groupBy != 2) { entry.nodeid = docs[i].nodeid; } + entry.protocol = docs[i].protocol; + + // Session length + if (((docs[i].msgid == 10) || (docs[i].msgid == 12)) && (docs[i].msgArgs != null) && (typeof docs[i].msgArgs == 'object') && (typeof docs[i].msgArgs[3] == 'number')) { entry.length = docs[i].msgArgs[3]; } + + if (command.groupBy == 1) { // Add entry to per user group + if (data.groups[docs[i].userid] == null) { data.groups[docs[i].userid] = { entries: [] }; } + data.groups[docs[i].userid].entries.push(entry); + } else if (command.groupBy == 2) { // Add entry to per device group + if (data.groups[docs[i].nodeid] == null) { data.groups[docs[i].nodeid] = { entries: [] }; } + data.groups[docs[i].nodeid].entries.push(entry); + } else if (command.groupBy == 3) { // Add entry to per day group + var day; + if ((typeof command.l == 'string') && (typeof command.tz == 'string')) { + day = new Date(docs[i].time).toLocaleDateString(command.l, { timeZone: command.tz }); + } else { + day = docs[i].time; // TODO + } + if (data.groups[day] == null) { data.groups[day] = { entries: [] }; } + data.groups[day].entries.push(entry); + } + + } + try { ws.send(JSON.stringify({ action: 'report', data: data })); } catch (ex) { } + }); + } + break; + } default: { // Unknown user action console.log('Unknown action from user ' + user.name + ': ' + command.action + '.'); diff --git a/public/styles/style.css b/public/styles/style.css index d765338e..c60b5eff 100644 --- a/public/styles/style.css +++ b/public/styles/style.css @@ -273,7 +273,7 @@ body { } /* #UserDummyMenuSpan, */ -#MainSubMenuSpan, #MeshSubMenuSpan, #UserSubMenuSpan, #UsersSubMenuSpan, #ServerSubMenuSpan, #MainMenuSpan, #MainSubMenu, #MeshSubMenu, #UserSubMenu, #ServerSubMenu, #UserDummyMenu, #PluginSubMenu { +#MainSubMenuSpan, #MeshSubMenuSpan, #EventsSubMenuSpan, #UserSubMenuSpan, #UsersSubMenuSpan, #ServerSubMenuSpan, #MainMenuSpan, #MainSubMenu, #MeshSubMenu, #UserSubMenu, #ServerSubMenu, #UserDummyMenu, #PluginSubMenu { width: 100%; height: 24px; color: white; diff --git a/views/default.handlebars b/views/default.handlebars index a31a6464..ce5cd576 100644 --- a/views/default.handlebars +++ b/views/default.handlebars @@ -209,6 +209,15 @@ + +