diff --git a/Server/Pages/EditDevice.cshtml.cs b/Server/Pages/EditDevice.cshtml.cs index fb3fe226..24a1aec3 100644 --- a/Server/Pages/EditDevice.cshtml.cs +++ b/Server/Pages/EditDevice.cshtml.cs @@ -31,10 +31,21 @@ namespace Remotely.Server.Pages private DataService DataService { get; } - public void OnGet(string deviceID, bool success) + public IActionResult OnGet(string deviceID, bool success) { + var user = DataService.GetUserByName(User.Identity.Name); + if (!DataService.DoesUserHaveAccessToDevice(deviceID, user)) + { + var targetDevice = DataService.GetDevice(deviceID); + DataService.WriteEvent($"Edit device attempted by unauthorized user. Device ID: {deviceID}. User Name: {user.UserName}.", + Remotely.Shared.Models.EventType.Warning, + targetDevice.OrganizationID); + return Unauthorized(); + } SaveSucessful = success; PopulateViewModel(deviceID); + + return Page(); } public IActionResult OnPost(string deviceID) diff --git a/Server/Services/BrowserSocketHub.cs b/Server/Services/BrowserSocketHub.cs index 17684a7f..093b6ce0 100644 --- a/Server/Services/BrowserSocketHub.cs +++ b/Server/Services/BrowserSocketHub.cs @@ -134,9 +134,9 @@ namespace Remotely.Server.Services public Task RemoteControl(string deviceID) { - if (DataService.DoesUserHaveAccessToDevice(deviceID, RemotelyUser)) + var targetDevice = DeviceSocketHub.ServiceConnections.FirstOrDefault(x => x.Value.ID == deviceID); + if (DataService.DoesUserHaveAccessToDevice(deviceID, RemotelyUser)) { - var targetDevice = DeviceSocketHub.ServiceConnections.FirstOrDefault(x => x.Value.ID == deviceID); var currentUsers = RCDeviceSocketHub.SessionInfoList.Count(x => x.Value.OrganizationID == RemotelyUser.OrganizationID); if (currentUsers >= AppConfig.RemoteControlSessionLimit) { @@ -145,6 +145,10 @@ namespace Remotely.Server.Services Clients.Caller.SendAsync("ServiceID", targetDevice.Key); return DeviceHub.Clients.Client(targetDevice.Key).SendAsync("RemoteControl", Context.ConnectionId, targetDevice.Key); } + else + { + DataService.WriteEvent($"Remote control attempted by unauthorized user. Device ID: {deviceID}. User Name: {RemotelyUser.UserName}.", EventType.Warning, targetDevice.Value.OrganizationID); + } return Task.CompletedTask; } diff --git a/Server/Services/DataService.cs b/Server/Services/DataService.cs index 2c02c812..0b52bb7d 100644 --- a/Server/Services/DataService.cs +++ b/Server/Services/DataService.cs @@ -380,12 +380,12 @@ namespace Remotely.Server.Services return RemotelyContext.Devices .Include(x => x.DeviceGroup) .ThenInclude(x => x.PermissionLinks) - .Any(x => x.OrganizationID == remotelyUser.OrganizationID && - x.ID == deviceID && + .Any(device => device.OrganizationID == remotelyUser.OrganizationID && + device.ID == deviceID && ( remotelyUser.IsAdministrator || - x.DeviceGroup.PermissionLinks.Count == 0 || - x.DeviceGroup.PermissionLinks.Any(x => x.UserID == remotelyUser.Id + device.DeviceGroup.PermissionLinks.Count == 0 || + device.DeviceGroup.PermissionLinks.Any(permission => permission.UserID == remotelyUser.Id ))); } @@ -401,18 +401,42 @@ namespace Remotely.Server.Services return RemotelyContext.Devices .Include(x => x.DeviceGroup) .ThenInclude(x => x.PermissionLinks) - .Where(x => - x.OrganizationID == remotelyUser.OrganizationID && - deviceIDs.Contains(x.ID) && + .Where(device => + device.OrganizationID == remotelyUser.OrganizationID && + deviceIDs.Contains(device.ID) && ( remotelyUser.IsAdministrator || - x.DeviceGroup.PermissionLinks.Count == 0 || - x.DeviceGroup.PermissionLinks.Any(x => x.UserID == remotelyUser.Id + device.DeviceGroup.PermissionLinks.Count == 0 || + device.DeviceGroup.PermissionLinks.Any(permission => permission.UserID == remotelyUser.Id ))) .Select(x => x.ID) .ToArray(); } + public IEnumerable FilterUsersByDevicePermission(IEnumerable userIDs, string deviceID) + { + var device = RemotelyContext.Devices + .Include(x => x.DeviceGroup) + .ThenInclude(x => x.PermissionLinks) + .FirstOrDefault(x => x.ID == deviceID); + + var allowedUsers = device.DeviceGroup.PermissionLinks.Select(x => x.UserID); + + return RemotelyContext.Users + .Include(x => x.PermissionLinks) + .Where(user => + user.OrganizationID == device.OrganizationID && + userIDs.Contains(user.Id) && + ( + user.IsAdministrator || + device.DeviceGroup.PermissionLinks.Count == 0 || + allowedUsers.Contains(user.Id) + ) + ) + .Select(x => x.Id); + } + + public IEnumerable GetAllApiTokens(string userID) { var user = RemotelyContext.Users.FirstOrDefault(x => x.Id == userID); @@ -493,6 +517,11 @@ namespace Remotely.Server.Services x.ID == deviceID); } + public Device GetDevice(string deviceID) + { + return RemotelyContext.Devices.FirstOrDefault(x => x.ID == deviceID); + } + public int GetDeviceCount() { return RemotelyContext.Devices.Count(); @@ -533,7 +562,7 @@ namespace Remotely.Server.Services ( user.IsAdministrator || x.DeviceGroup.PermissionLinks.Count == 0 || - x.DeviceGroup.PermissionLinks.Any(x => x.UserID == userID + x.DeviceGroup.PermissionLinks.Any(permission => permission.UserID == userID ))); } diff --git a/Server/Services/DeviceSocketHub.cs b/Server/Services/DeviceSocketHub.cs index 67d9d9a0..56f94b8b 100644 --- a/Server/Services/DeviceSocketHub.cs +++ b/Server/Services/DeviceSocketHub.cs @@ -92,11 +92,16 @@ namespace Remotely.Server.Services { Device = updatedDevice; ServiceConnections.AddOrUpdate(Context.ConnectionId, Device, (id, d) => Device); + + var userIDs = BrowserSocketHub.ConnectionIdToUserLookup.Values.Select(x => x.Id); + + var filteredUserIDs = DataService.FilterUsersByDevicePermission(userIDs, Device.ID); var connectionIds = BrowserSocketHub.ConnectionIdToUserLookup - .Where(x => x.Value.OrganizationID == Device.OrganizationID) - .Select(x => x.Key) - .ToList(); + .Where(x => x.Value.OrganizationID == Device.OrganizationID && + filteredUserIDs.Contains(x.Value.Id)) + .Select(x => x.Key) + .ToList(); BrowserHub.Clients.Clients(connectionIds).SendAsync("DeviceCameOnline", Device); return Task.FromResult(true); @@ -120,10 +125,16 @@ namespace Remotely.Server.Services { DataService.AddOrUpdateDevice(device, out var updatedDevice); Device = updatedDevice; + + var userIDs = BrowserSocketHub.ConnectionIdToUserLookup.Values.Select(x => x.Id); + + var filteredUserIDs = DataService.FilterUsersByDevicePermission(userIDs, Device.ID); + var connectionIds = BrowserSocketHub.ConnectionIdToUserLookup - .Where(x => x.Value.OrganizationID == Device.OrganizationID) - .Select(x => x.Key) - .ToList(); + .Where(x => x.Value.OrganizationID == Device.OrganizationID && + filteredUserIDs.Contains(x.Value.Id)) + .Select(x => x.Key) + .ToList(); return BrowserHub.Clients.Clients(connectionIds).SendAsync("DeviceHeartbeat", Device); }