mirror of
				https://github.com/Ylianst/MeshCentral.git
				synced 2025-03-09 15:40:18 +00:00 
			
		
		
		
	Added user login report.
This commit is contained in:
		
							parent
							
								
									bb7af0402d
								
							
						
					
					
						commit
						eae865ab8d
					
				
					 4 changed files with 101 additions and 11 deletions
				
			
		
							
								
								
									
										79
									
								
								meshuser.js
									
										
									
									
									
								
							
							
						
						
									
										79
									
								
								meshuser.js
									
										
									
									
									
								
							| 
						 | 
					@ -5914,18 +5914,27 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function serverCommandReport(command) {
 | 
					    function serverCommandReport(command) {
 | 
				
			||||||
        if (common.validateInt(command.type, 1, 2) == false) return; // Validate type
 | 
					        if (common.validateInt(command.type, 1, 3) == false) return; // Validate type
 | 
				
			||||||
        if (common.validateInt(command.groupBy, 1, 3) == false) return; // Validate groupBy: 1 = User, 2 = Device, 3 = Day
 | 
					        if (common.validateInt(command.groupBy, 1, 3) == false) return; // Validate groupBy: 1 = User, 2 = Device, 3 = Day
 | 
				
			||||||
        if ((typeof command.start != 'number') || (typeof command.end != 'number') || (command.start >= command.end)) return; // Validate start and end time
 | 
					        if ((typeof command.start != 'number') || (typeof command.end != 'number') || (command.start >= command.end)) return; // Validate start and end time
 | 
				
			||||||
        const manageAllDeviceGroups = ((user.siteadmin == 0xFFFFFFFF) && (parent.parent.config.settings.managealldevicegroups.indexOf(user._id) >= 0));
 | 
					        const manageAllDeviceGroups = ((user.siteadmin == 0xFFFFFFFF) && (parent.parent.config.settings.managealldevicegroups.indexOf(user._id) >= 0));
 | 
				
			||||||
        if ((command.devGroup != null) && (manageAllDeviceGroups == false) && ((user.links == null) || (user.links[command.devGroup] == null))) return; // Asking for a device group that is not allowed
 | 
					        if ((command.devGroup != null) && (manageAllDeviceGroups == false) && ((user.links == null) || (user.links[command.devGroup] == null))) return; // Asking for a device group that is not allowed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const msgIdFilter = [5, 10, 11, 12, 122, 123, 124, 125, 126];
 | 
					        const msgIdFilter = [5, 10, 11, 12, 122, 123, 124, 125, 126];
 | 
				
			||||||
 | 
					        switch (command.type) {
 | 
				
			||||||
        if (command.type == 1)
 | 
					            case 1: {
 | 
				
			||||||
            remoteSessionReport(command, manageAllDeviceGroups, msgIdFilter);
 | 
					                remoteSessionReport(command, manageAllDeviceGroups, msgIdFilter);
 | 
				
			||||||
        if (command.type == 2)
 | 
					                break;
 | 
				
			||||||
            trafficUsageReport(command, msgIdFilter);
 | 
					            }
 | 
				
			||||||
 | 
					            case 2: {
 | 
				
			||||||
 | 
					                trafficUsageReport(command, msgIdFilter);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            case 3: {
 | 
				
			||||||
 | 
					                userLoginReport(command, msgIdFilter);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }   
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function serverCommandServerClearErrorLog(command) {
 | 
					    function serverCommandServerClearErrorLog(command) {
 | 
				
			||||||
| 
						 | 
					@ -6939,7 +6948,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // Fetch or create the user entry
 | 
					                // Fetch or create the user entry
 | 
				
			||||||
                var userEntry = userEntries[docs[i].userid];
 | 
					                var userEntry = userEntries[docs[i].userid];
 | 
				
			||||||
                if (userEntry == null) { userEntry = { userid: docs[i].userid, length: 0, bytesin: 0, bytesout: 0}; }
 | 
					                if (userEntry == null) { userEntry = { userid: docs[i].userid, length: 0, bytesin: 0, bytesout: 0 }; }
 | 
				
			||||||
                if (docs[i].bytesin) { userEntry.bytesin += docs[i].bytesin; }
 | 
					                if (docs[i].bytesin) { userEntry.bytesin += docs[i].bytesin; }
 | 
				
			||||||
                if (docs[i].bytesout) { userEntry.bytesout += docs[i].bytesout; }
 | 
					                if (docs[i].bytesout) { userEntry.bytesout += docs[i].bytesout; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6959,6 +6968,62 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function userLoginReport(command) {
 | 
				
			||||||
 | 
					        // If we are not user administrator on this site, only search for events with our own user id.
 | 
				
			||||||
 | 
					        var ids = [user._id]; // If we are nto user administrator, only count our own traffic.
 | 
				
			||||||
 | 
					        if ((user.siteadmin & SITERIGHT_MANAGEUSERS) != 0) { ids = ['*']; } // If user administrator, count traffic of all users.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var showInvalidLoginAttempts = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Get the events in the time range
 | 
				
			||||||
 | 
					        // MySQL or MariaDB query will ignore the MsgID filter.
 | 
				
			||||||
 | 
					        var msgIdFilter = [107];
 | 
				
			||||||
 | 
					        if (showInvalidLoginAttempts) { msgIdFilter = [107, 108, 109, 110]; } // Includes invalid login attempts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        db.GetEventsTimeRange(ids, domain.id, msgIdFilter, new Date(command.start * 1000), new Date(command.end * 1000), function (err, docs) {
 | 
				
			||||||
 | 
					            if (err != null) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Columns
 | 
				
			||||||
 | 
					            var data = { groups: {} };
 | 
				
			||||||
 | 
					            if (command.groupBy == 1) {
 | 
				
			||||||
 | 
					                data.groupFormat = 'user';
 | 
				
			||||||
 | 
					                data.columns = [{ id: 'time', title: "time", format: 'datetime' }, { id: 'ip', title: "ip" }, { id: 'browser', title: "browser" }, { id: 'os', title: "os" }];
 | 
				
			||||||
 | 
					            } else if (command.groupBy == 3) {
 | 
				
			||||||
 | 
					                data.columns = [{ id: 'time', title: "time", format: 'time' }, { id: 'userid', title: "user", format: 'user' }, { id: 'ip', title: "ip" }, { id: 'browser', title: "browser" }, { id: 'os', title: "os" }];
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (showInvalidLoginAttempts) { data.columns.push({ id: 'msg', title: "msg", format: 'msg' }); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Add all log entries
 | 
				
			||||||
 | 
					            var entries = [];
 | 
				
			||||||
 | 
					            for (var i in docs) {
 | 
				
			||||||
 | 
					                // If MySQL or MariaDB query, we can't filter on MsgID, so we have to do it here.
 | 
				
			||||||
 | 
					                if (msgIdFilter.indexOf(docs[i].msgid) < 0) continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (command.groupBy == 1) { // Add entry per user
 | 
				
			||||||
 | 
					                    if (data.groups[docs[i].userid] == null) { data.groups[docs[i].userid] = { entries: [] }; }
 | 
				
			||||||
 | 
					                    const entry = { time: docs[i].time.valueOf(), ip: docs[i].msgArgs[0], browser: docs[i].msgArgs[1], os: docs[i].msgArgs[2] };
 | 
				
			||||||
 | 
					                    if (showInvalidLoginAttempts) { entry.msg = docs[i].msgid }
 | 
				
			||||||
 | 
					                    data.groups[docs[i].userid].entries.push(entry);
 | 
				
			||||||
 | 
					                } else if (command.groupBy == 3) { // Add entry per day
 | 
				
			||||||
 | 
					                    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: [] }; }
 | 
				
			||||||
 | 
					                    const entry = { time: docs[i].time.valueOf(), userid: docs[i].userid, ip: docs[i].msgArgs[0], browser: docs[i].msgArgs[1], os: docs[i].msgArgs[2] };
 | 
				
			||||||
 | 
					                    if (showInvalidLoginAttempts) { entry.msg = docs[i].msgid }
 | 
				
			||||||
 | 
					                    data.groups[day].entries.push(entry);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            try { ws.send(JSON.stringify({ action: 'report', data: data })); } catch (ex) { }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Return detailed information about an array of nodeid's
 | 
					    // Return detailed information about an array of nodeid's
 | 
				
			||||||
    function getDeviceDetailedInfo(nodeids, type, func) {
 | 
					    function getDeviceDetailedInfo(nodeids, type, func) {
 | 
				
			||||||
        if (nodeids == null) { getAllDeviceDetailedInfo(type, func); return; }
 | 
					        if (nodeids == null) { getAllDeviceDetailedInfo(type, func); return; }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								public/images/notify16.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								public/images/notify16.png
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 5.8 KiB  | 
| 
						 | 
					@ -848,6 +848,15 @@ NoMeshesPanel img {
 | 
				
			||||||
.NotifyIconSmall7 { width:24px; height:24px; background: url(../images/notify24.png) -144px 0px; }
 | 
					.NotifyIconSmall7 { width:24px; height:24px; background: url(../images/notify24.png) -144px 0px; }
 | 
				
			||||||
.NotifyIconSmall8 { width:24px; height:24px; background: url(../images/notify24.png) -168px 0px; }
 | 
					.NotifyIconSmall8 { width:24px; height:24px; background: url(../images/notify24.png) -168px 0px; }
 | 
				
			||||||
.NotifyIconSmall9 { width:24px; height:24px; background: url(../images/notify24.png) -192px 0px; }
 | 
					.NotifyIconSmall9 { width:24px; height:24px; background: url(../images/notify24.png) -192px 0px; }
 | 
				
			||||||
 | 
					.NotifyIconTiny1 { width:16px; height:16px; background: url(../images/notify16.png) 0px 0px; }
 | 
				
			||||||
 | 
					.NotifyIconTiny2 { width:16px; height:16px; background: url(../images/notify16.png) -16px 0px; }
 | 
				
			||||||
 | 
					.NotifyIconTiny3 { width:16px; height:16px; background: url(../images/notify16.png) -32px 0px; }
 | 
				
			||||||
 | 
					.NotifyIconTiny4 { width:16px; height:16px; background: url(../images/notify16.png) -48px 0px; }
 | 
				
			||||||
 | 
					.NotifyIconTiny5 { width:16px; height:16px; background: url(../images/notify16.png) -64px 0px; }
 | 
				
			||||||
 | 
					.NotifyIconTiny6 { width:16px; height:16px; background: url(../images/notify16.png) -80px 0px; }
 | 
				
			||||||
 | 
					.NotifyIconTiny7 { width:16px; height:16px; background: url(../images/notify16.png) -96px 0px; }
 | 
				
			||||||
 | 
					.NotifyIconTiny8 { width:16px; height:16px; background: url(../images/notify16.png) -112px 0px; }
 | 
				
			||||||
 | 
					.NotifyIconTiny9 { width:16px; height:16px; background: url(../images/notify16.png) -128px 0px; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.deviceBatteryLarge {
 | 
					.deviceBatteryLarge {
 | 
				
			||||||
    position:absolute;
 | 
					    position:absolute;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15623,7 +15623,7 @@
 | 
				
			||||||
            if (xxdialogMode) return;
 | 
					            if (xxdialogMode) return;
 | 
				
			||||||
            var y = '', x = '', settings = JSON.parse(getstore('_ReportSettings', '{}'));
 | 
					            var y = '', x = '', settings = JSON.parse(getstore('_ReportSettings', '{}'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var options = { 1 : "Remote Sessions", 2 : "User Traffic Usage" }
 | 
					            var options = { 1 : "Remote Sessions", 2 : "User Traffic Usage", 3 : "User Logins" }
 | 
				
			||||||
            for (var i in options) { y += '<option value=' + i + ((settings.type == i)?' selected':'') + '>' + options[i] + '</option>'; }
 | 
					            for (var i in options) { y += '<option value=' + i + ((settings.type == i)?' selected':'') + '>' + options[i] + '</option>'; }
 | 
				
			||||||
            x += addHtmlValue("Type", '<select id=d2reportType style=float:right;width:250px onchange=generateReportDialogValidate()>' + y + '</select>');
 | 
					            x += addHtmlValue("Type", '<select id=d2reportType style=float:right;width:250px onchange=generateReportDialogValidate()>' + y + '</select>');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15634,6 +15634,13 @@
 | 
				
			||||||
            x += addHtmlValue("Group by", '<select id=d2groupBy style=float:right;width:250px onchange=generateReportDialogValidate()>' + y + '</select>');
 | 
					            x += addHtmlValue("Group by", '<select id=d2groupBy style=float:right;width:250px onchange=generateReportDialogValidate()>' + y + '</select>');
 | 
				
			||||||
            x += '</div>';
 | 
					            x += '</div>';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            x += '<div id=d2GroupByDiv2 style=display:none>';
 | 
				
			||||||
 | 
					            y = '';
 | 
				
			||||||
 | 
					            var options = { 1 : "User", 3: "Day" }
 | 
				
			||||||
 | 
					            for (var i in options) { y += '<option value=' + i + ((settings.groupBy2 == i)?' selected':'') + '>' + options[i] + '</option>'; }
 | 
				
			||||||
 | 
					            x += addHtmlValue("Group by", '<select id=d2groupBy2 style=float:right;width:250px onchange=generateReportDialogValidate()>' + y + '</select>');
 | 
				
			||||||
 | 
					            x += '</div>';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            x += '<div id=d2DeviceGroupDiv style=display:none>';
 | 
					            x += '<div id=d2DeviceGroupDiv style=display:none>';
 | 
				
			||||||
            y = '<option value=0' + ((settings.devGroup == 0)?' selected':'') + '>' + "All" + '</option>';
 | 
					            y = '<option value=0' + ((settings.devGroup == 0)?' selected':'') + '>' + "All" + '</option>';
 | 
				
			||||||
            var omeshs = getOrderedList(meshes, 'name');
 | 
					            var omeshs = getOrderedList(meshes, 'name');
 | 
				
			||||||
| 
						 | 
					@ -15667,6 +15674,7 @@
 | 
				
			||||||
        function generateReportDialogValidate() {
 | 
					        function generateReportDialogValidate() {
 | 
				
			||||||
            QV('d2timeRangeDiv', Q('d2timeRange').value == 0);
 | 
					            QV('d2timeRangeDiv', Q('d2timeRange').value == 0);
 | 
				
			||||||
            QV('d2GroupByDiv', Q('d2reportType').value == 1);
 | 
					            QV('d2GroupByDiv', Q('d2reportType').value == 1);
 | 
				
			||||||
 | 
					            QV('d2GroupByDiv2', Q('d2reportType').value == 3);
 | 
				
			||||||
            QV('d2DeviceGroupDiv', Q('d2reportType').value == 1);
 | 
					            QV('d2DeviceGroupDiv', Q('d2reportType').value == 1);
 | 
				
			||||||
            QV('d2showTrafficDiv', Q('d2reportType').value == 1);
 | 
					            QV('d2showTrafficDiv', Q('d2reportType').value == 1);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -15685,12 +15693,14 @@
 | 
				
			||||||
            try { tz = Intl.DateTimeFormat().resolvedOptions().timeZone; } catch (ex) {}
 | 
					            try { tz = Intl.DateTimeFormat().resolvedOptions().timeZone; } catch (ex) {}
 | 
				
			||||||
            var devGroup = decodeURIComponent(Q('d2groupId').value);
 | 
					            var devGroup = decodeURIComponent(Q('d2groupId').value);
 | 
				
			||||||
            if (devGroup == 0) { devGroup = null; }
 | 
					            if (devGroup == 0) { devGroup = null; }
 | 
				
			||||||
            putstore('_ReportSettings', JSON.stringify({ type: parseInt(Q('d2reportType').value), groupBy: parseInt(Q('d2groupBy').value), timeRange: parseInt(Q('d2timeRange').value), devGroup: devGroup, showTraffic: Q('d2showTraffic').checked }));
 | 
					            putstore('_ReportSettings', JSON.stringify({ type: parseInt(Q('d2reportType').value), groupBy: parseInt(Q('d2groupBy').value), groupBy2: parseInt(Q('d2groupBy2').value), timeRange: parseInt(Q('d2timeRange').value), devGroup: devGroup, showTraffic: Q('d2showTraffic').checked }));
 | 
				
			||||||
            meshserver.send({ action: 'report', type: parseInt(Q('d2reportType').value), groupBy: parseInt(Q('d2groupBy').value), start: start, end: end, tz: tz, tf: new Date().getTimezoneOffset(), l: getLang(), devGroup: devGroup, showTraffic: Q('d2showTraffic').checked });
 | 
					            var groupBy = parseInt(Q('d2groupBy').value);
 | 
				
			||||||
 | 
					            if (Q('d2reportType').value == 3) { groupBy = parseInt(Q('d2groupBy2').value); }
 | 
				
			||||||
 | 
					            meshserver.send({ action: 'report', type: parseInt(Q('d2reportType').value), groupBy: groupBy, start: start, end: end, tz: tz, tf: new Date().getTimezoneOffset(), l: getLang(), devGroup: devGroup, showTraffic: Q('d2showTraffic').checked });
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        function renderReport(r) {
 | 
					        function renderReport(r) {
 | 
				
			||||||
            var colTranslation = { time: "Time", device: "Device", session: "Session", user: "User", devgroup: "Device Group", guest: "Guest", length: "Length", bytesin: "Bytes In", bytesout: "Bytes Out" }
 | 
					            var colTranslation = { time: "Time", device: "Device", session: "Session", user: "User", devgroup: "Device Group", guest: "Guest", length: "Length", bytesin: "Bytes In", bytesout: "Bytes Out", os: "Operating System", ip: "IP Address", browser: "Browser", msg: "Message" }
 | 
				
			||||||
            var x = '<table style=width:100%>', firstItem;
 | 
					            var x = '<table style=width:100%>', firstItem;
 | 
				
			||||||
            var sumByCol = null; // Indicate by what colum we sum by
 | 
					            var sumByCol = null; // Indicate by what colum we sum by
 | 
				
			||||||
            var sumByValues = []; // Indicate by what values we sum by
 | 
					            var sumByValues = []; // Indicate by what values we sum by
 | 
				
			||||||
| 
						 | 
					@ -15844,6 +15854,12 @@
 | 
				
			||||||
                    return '<i>' + "Unknown User" + '</i>';
 | 
					                    return '<i>' + "Unknown User" + '</i>';
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            if (f == 'msg') {
 | 
				
			||||||
 | 
					                if (v == 107) return '<div style=float:left;margin-right:4px;cursor:pointer class="NotifyIconTiny1"></div>' + "Succesful login";
 | 
				
			||||||
 | 
					                if (v == 108) return '<div style=float:left;margin-right:4px;cursor:pointer class="NotifyIconTiny2"></div>' + "Incorrect 2nd factor";
 | 
				
			||||||
 | 
					                if (v == 109) return '<div style=float:left;margin-right:4px;cursor:pointer class="NotifyIconTiny4"></div>' + "Locked account";
 | 
				
			||||||
 | 
					                if (v == 110) return '<div style=float:left;margin-right:4px;cursor:pointer class="NotifyIconTiny3"></div>' + "Invalid login attempt";
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            return EscapeHtml(v);
 | 
					            return EscapeHtml(v);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue