using Remotely_Shared.Models; using Remotely_Shared.ViewModels; using Remotely_Server.Services; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using System; using System.Collections.Generic; using System.IO; using System.Linq; namespace Remotely_Server.Data { public class DataService { public DataService( ApplicationDbContext context, ApplicationConfig appConfig, UserManager userManager ) { RemotelyContext = context; AppConfig = appConfig; UserManager = userManager; } private ApplicationConfig AppConfig { get; set; } private ApplicationDbContext RemotelyContext { get; set; } private UserManager UserManager { get; set; } public void AddOrUpdateCommandContext(CommandContext commandContext) { var existingContext = RemotelyContext.CommandContexts.Find(commandContext.ID); if (existingContext != null) { var entry = RemotelyContext.Entry(existingContext); entry.CurrentValues.SetValues(commandContext); entry.State = EntityState.Modified; } else { RemotelyContext.CommandContexts.Add(commandContext); } RemotelyContext.SaveChanges(); } public bool AddOrUpdateDevice(Device device) { var existingDevice = RemotelyContext.Devices.Find(device.ID); if (existingDevice != null) { device.ServerVerificationToken = existingDevice.ServerVerificationToken; RemotelyContext.Entry(existingDevice).CurrentValues.SetValues(device); } else { if (!RemotelyContext.Organizations.Any(x => x.ID == device.OrganizationID)) { WriteEvent(new EventLog() { EventType = EventTypes.Info, Message = $"Unable to add device {device.DeviceName} because organization {device.OrganizationID} does not exist.", Source = "DataService.AddOrUpdateDevice" }); return false; } RemotelyContext.Devices.Add(device); } RemotelyContext.SaveChanges(); return true; } public IEnumerable GetDevicesAndPermissions(string userID, string[] deviceIDs) { var user = GetUserByID(userID); var devices = RemotelyContext.Devices .Include(x => x.DevicePermissionLinks) .Include("DevicePermissionLinks.PermissionGroup") .Where(x => x.OrganizationID == user.OrganizationID) .ToList(); return devices.Select(x => new Device() { DeviceName = x.DeviceName, DevicePermissionLinks = x.DevicePermissionLinks.ToList() }); } public void CleanupEmptyOrganizations() { var emptyOrgs = RemotelyContext.Organizations .Include(x => x.RemotelyUsers) .Include(x => x.CommandContexts) .Include(x => x.InviteLinks) .Include(x => x.Devices) .Include(x => x.SharedFiles) .Include(x => x.PermissionGroups) .Include(x => x.EventLogs) .Where(x => x.RemotelyUsers.Count == 0); foreach (var emptyOrg in emptyOrgs) { RemotelyContext.Remove(emptyOrg); } RemotelyContext.SaveChanges(); } public bool DoesUserExist(string userName) { if (userName == null) { return false; } return RemotelyContext.Users.Any(x => x.UserName == userName); } public bool DoesUserHaveAccessToDevice(string deviceID, RemotelyUser remotelyUser) { var targetDevice = RemotelyContext.Devices .Include(x=>x.DevicePermissionLinks) .FirstOrDefault(x => x.ID == deviceID && x.OrganizationID == remotelyUser.OrganizationID); return remotelyUser.IsAdministrator || targetDevice.DevicePermissionLinks.Count == 0 || targetDevice.DevicePermissionLinks.Any(x => x.PermissionGroup.UserPermissionLinks.Any(y => y.RemotelyUserID == remotelyUser.Id)); } public string[] FilterDeviceIDsByUserPermission(string[] deviceIDs, RemotelyUser remotelyUser) { return RemotelyContext.Devices.Where(x => deviceIDs.Contains(x.ID) && x.OrganizationID == remotelyUser.OrganizationID && ( remotelyUser.IsAdministrator || x.DevicePermissionLinks.Count == 0 || x.DevicePermissionLinks.Any(y => y.PermissionGroup.UserPermissionLinks.Any(z => z.RemotelyUserID == remotelyUser.Id)) )) .Select(x => x.ID) .ToArray(); } public IEnumerable GetAllCommandContexts(string userName) { var orgID = GetUserByName(userName).OrganizationID; return RemotelyContext.CommandContexts.Where(x => x.OrganizationID == orgID); } public IEnumerable GetAllDevicesForUser(string userID) { var user = RemotelyContext.Users .Include(x => x.UserPermissionLinks) .FirstOrDefault(x => x.Id == userID); var result = RemotelyContext.Devices .Include(x => x.DevicePermissionLinks) .Where(x => x.OrganizationID == user.OrganizationID); if (user.IsAdministrator) { return result; } else { return result.Where(x => x.DevicePermissionLinks.Count == 0 || x.DevicePermissionLinks.Any(y => y.PermissionGroup.UserPermissionLinks.Any(z => z.RemotelyUserID == user.Id))); } } public IEnumerable GetAllPermissions(string userName) { return RemotelyContext.Users .Include(x => x.Organization) .ThenInclude(x => x.PermissionGroups) .FirstOrDefault(x => x.UserName == userName) .Organization.PermissionGroups; } public CommandContext GetCommandContext(string commandContextID, string userName) { var user = GetUserByName(userName); return RemotelyContext.CommandContexts .FirstOrDefault(x => (user.IsAdministrator || x.SenderUserID == user.Id) && x.OrganizationID == user.OrganizationID && x.ID == commandContextID); } public CommandContext GetCommandContext(string commandContextID) { return RemotelyContext.CommandContexts.Find(commandContextID); } public string GetDefaultPrompt(string userName) { var userPrompt = RemotelyContext.Users.FirstOrDefault(x => x.UserName == userName)?.UserOptions?.ConsolePrompt; return userPrompt ?? AppConfig.DefaultPrompt; } public string GetDefaultPrompt() { return AppConfig.DefaultPrompt; } public Device GetDeviceForUser(string userID, string deviceID) { var user = RemotelyContext.Users .Include(x => x.UserPermissionLinks) .FirstOrDefault(x => x.Id == userID); var result = RemotelyContext.Devices .Include(x => x.DevicePermissionLinks) .Where(x => x.OrganizationID == user.OrganizationID && x.ID == deviceID); if (!user.IsAdministrator) { result = result.Where(x => x.DevicePermissionLinks.Count == 0 || x.DevicePermissionLinks.Any(y => y.PermissionGroup.UserPermissionLinks.Any(z => z.RemotelyUserID == user.Id))); } return result.FirstOrDefault(); } public RemotelyUser GetUserAndPermissionsByID(string userID) { if (userID == null) { return null; } return RemotelyContext.Users .Include(x => x.Organization) .Include(x => x.UserPermissionLinks) .FirstOrDefault(x => x.Id == userID); } public RemotelyUser GetUserByID(string userID) { if (userID == null) { return null; } return RemotelyContext.Users.FirstOrDefault(x => x.Id == userID); } public RemotelyUser GetUserByName(string userName) { if (userName == null) { return null; } return RemotelyContext.Users .Include(x => x.Organization) .FirstOrDefault(x => x.UserName == userName); } public void DeviceDisconnected(string deviceID) { var device = RemotelyContext.Devices.Find(deviceID); if (device != null) { device.LastOnline = DateTime.Now; device.IsOnline = false; RemotelyContext.SaveChanges(); } } public void RemoveDevices(string[] deviceIDs) { var devices = RemotelyContext.Devices .Where(x => deviceIDs.Contains(x.ID)); RemotelyContext.Devices.RemoveRange(devices); RemotelyContext.SaveChanges(); } public void SetAllDevicesNotOnline() { RemotelyContext.Devices.ForEachAsync(x => { x.IsOnline = false; }).Wait(); RemotelyContext.SaveChanges(); } public void WriteEvent(EventLog eventLog) { RemotelyContext.EventLogs.Add(eventLog); RemotelyContext.SaveChanges(); } public void WriteEvent(Exception ex) { RemotelyContext.EventLogs.Add(new EventLog() { EventType = EventTypes.Error, Message = ex.Message, Source = ex.Source, StackTrace = ex.StackTrace, TimeStamp = DateTime.Now }); RemotelyContext.SaveChanges(); } public void WriteEvent(string message) { RemotelyContext.EventLogs.Add(new EventLog() { EventType = EventTypes.Info, Message = message, TimeStamp = DateTime.Now }); RemotelyContext.SaveChanges(); } internal InviteLink AddInvite(string requesterUserName, Invite invite, string requestOrigin) { invite.InvitedUser = invite.InvitedUser.ToLower(); var requester = RemotelyContext.Users .Include(x => x.Organization) .ThenInclude(x => x.InviteLinks) .Include(x => x.Organization) .ThenInclude(x => x.RemotelyUsers) .FirstOrDefault(x => x.UserName == requesterUserName); var newInvite = new InviteLink() { DateSent = DateTime.Now, InvitedUser = invite.InvitedUser, IsAdmin = invite.IsAdmin, Organization = requester.Organization }; requester.Organization.InviteLinks.Add(newInvite); RemotelyContext.SaveChanges(); return newInvite; } internal Tuple AddPermission(string userName, Permission permission) { var organization = RemotelyContext.Users .Include(x => x.Organization) .ThenInclude(x => x.PermissionGroups) .FirstOrDefault(x => x.UserName == userName) .Organization; if (organization.PermissionGroups.Any(x => x.Name.ToLower() == permission.Name.ToLower())) { return Tuple.Create(false, "Permission group already exists."); } var newPermission = new PermissionGroup() { Name = permission.Name, Organization = organization }; organization.PermissionGroups.Add(newPermission); RemotelyContext.SaveChanges(); return Tuple.Create(true, newPermission.ID); } internal void AddPermissionToDevices(string userID, string[] deviceIDs, string groupName) { var user = RemotelyContext.Users .Include(x => x.Organization) .Include(x => x.Organization) .ThenInclude(x => x.Devices) .FirstOrDefault(x => x.Id == userID); var group = user.Organization.PermissionGroups.FirstOrDefault(x => x.Name.ToLower() == groupName.ToLower()); foreach (var deviceID in deviceIDs) { if (user.Organization.Devices.Any(x => x.ID == deviceID)) { var device = RemotelyContext.Devices .Include(x => x.DevicePermissionLinks) .FirstOrDefault(x => x.ID == deviceID); if (!device.DevicePermissionLinks.Any(x => x.PermissionGroupID == group.ID)) { device.DevicePermissionLinks.Add(new DevicePermissionLink() { Device = device, DeviceID = device.ID, PermissionGroup = group, PermissionGroupID = group.ID }); RemotelyContext.Entry(device).State = EntityState.Modified; } } } RemotelyContext.SaveChanges(); } internal Tuple AddPermissionToUser(string requesterUserName, string targetUserID, string permissionID) { var requester = RemotelyContext.Users .Include(x => x.Organization) .FirstOrDefault(x => x.UserName == requesterUserName); var user = RemotelyContext.Users .Include(x => x.UserPermissionLinks) .FirstOrDefault(x => x.OrganizationID == requester.OrganizationID && x.Id == targetUserID); if (user.UserPermissionLinks.Any(x => x.PermissionGroupID == permissionID)) { return Tuple.Create(false, "User is already in the permission group."); } var permissions = RemotelyContext.PermissionGroups .Include(x => x.Organization) .Where(x => x.Organization.ID == requester.Organization.ID); var permission = permissions.FirstOrDefault(x => x.ID == permissionID); user.UserPermissionLinks.Add(new UserPermissionLink() { PermissionGroup = permission, PermissionGroupID = permission.ID, RemotelyUser = user, RemotelyUserID = user.Id }); RemotelyContext.SaveChanges(); return Tuple.Create(true, ""); } internal string AddSharedFile(IFormFile file) { var expiredFiles = RemotelyContext.SharedFiles.Where(x => DateTime.Now - x.Timestamp > TimeSpan.FromDays(7)); foreach (var expiredFile in expiredFiles) { RemotelyContext.Remove(expiredFile); } byte[] fileContents; using (var stream = file.OpenReadStream()) { using (var ms = new MemoryStream()) { stream.CopyTo(ms); fileContents = ms.ToArray(); } } var newEntity = RemotelyContext.Add(new SharedFile() { FileContents = fileContents, FileName = file.FileName, ContentType = file.ContentType }); RemotelyContext.SaveChanges(); return newEntity.Entity.ID; } internal void ChangeUserIsAdmin(string requesterUserName, string targetUserID, bool isAdmin) { var requester = RemotelyContext.Users .Include(x => x.Organization) .ThenInclude(x => x.RemotelyUsers) .FirstOrDefault(x => x.UserName == requesterUserName); requester.Organization.RemotelyUsers.FirstOrDefault(x => x.Id == targetUserID).IsAdministrator = isAdmin; RemotelyContext.SaveChanges(); } internal void CleanupOldRecords() { if (AppConfig.DataRetentionInDays > 0) { RemotelyContext.EventLogs .Where(x => DateTime.Now - x.TimeStamp > TimeSpan.FromDays(AppConfig.DataRetentionInDays)) .ForEachAsync(x => { RemotelyContext.Remove(x); }).Wait(); RemotelyContext.CommandContexts .Where(x => DateTime.Now - x.TimeStamp > TimeSpan.FromDays(AppConfig.DataRetentionInDays)) .ForEachAsync(x => { RemotelyContext.Remove(x); }).Wait(); RemotelyContext.Devices .Where(x => DateTime.Now - x.LastOnline > TimeSpan.FromDays(AppConfig.DataRetentionInDays)) .ForEachAsync(x => { RemotelyContext.Remove(x); }).Wait(); } } internal void DeleteInvite(string requesterUserName, string inviteID) { var requester = RemotelyContext.Users .Include(x => x.Organization) .ThenInclude(x => x.InviteLinks) .FirstOrDefault(x => x.UserName == requesterUserName); var invite = requester.Organization.InviteLinks.FirstOrDefault(x => x.ID == inviteID); RemotelyContext.Remove(invite); RemotelyContext.SaveChanges(); } internal void DeletePermission(string userName, string permissionID) { var organization = RemotelyContext.Users .Include(x => x.Organization) .ThenInclude(x => x.PermissionGroups) .FirstOrDefault(x => x.UserName == userName) .Organization; var permissionGroup = organization.PermissionGroups.FirstOrDefault(x => x.ID == permissionID); RemotelyContext.PermissionGroups.Remove(permissionGroup); RemotelyContext.SaveChanges(); } internal bool DoesGroupExist(string userID, string groupName) { var user = RemotelyContext.Users .Include(x => x.Organization) .ThenInclude(x => x.PermissionGroups) .FirstOrDefault(x => x.Id == userID); return user.Organization.PermissionGroups.Any(x => x.Name.ToLower() == groupName.ToLower()); } internal ICollection GetAllInviteLinks(string userName) { return RemotelyContext.Users .Include(x => x.Organization) .ThenInclude(x => x.InviteLinks) .FirstOrDefault(x => x.UserName == userName) .Organization .InviteLinks; } internal IEnumerable GetAllUsers(string userName) { return RemotelyContext.Users .Include(x => x.Organization) .ThenInclude(x => x.RemotelyUsers) .FirstOrDefault(x => x.UserName == userName) .Organization .RemotelyUsers; } internal string GetOrganizationName(string userName) { return RemotelyContext.Users .Include(x => x.Organization) .FirstOrDefault(x => x.UserName == userName) .Organization .OrganizationName; } internal SharedFile GetSharedFiled(string id) { return RemotelyContext.SharedFiles.Find(id); } internal RemotelyUserOptions GetUserOptions(string userName) { return RemotelyContext.Users .FirstOrDefault(x => x.UserName == userName) .UserOptions; } internal IEnumerable GetUserPermissions(string requesterUserName, string targetID) { var requester = GetUserByName(requesterUserName); var targetUser = RemotelyContext.Users .Include(x => x.Organization) .Include("UserPermissionLinks.PermissionGroup") .FirstOrDefault(x => x.OrganizationID == requester.OrganizationID && x.Id == targetID); return targetUser.UserPermissionLinks; } internal bool JoinViaInvitation(string userName, string inviteID) { var invite = RemotelyContext.InviteLinks .Include(x => x.Organization) .ThenInclude(x => x.RemotelyUsers) .FirstOrDefault(x => x.InvitedUser.ToLower() == userName.ToLower() && x.ID == inviteID); if (invite == null) { return false; } var user = RemotelyContext.Users .Include(x => x.Organization) .Include(x => x.UserPermissionLinks) .FirstOrDefault(x => x.UserName == userName); user.Organization = invite.Organization; user.OrganizationID = invite.Organization.ID; user.IsAdministrator = invite.IsAdmin; user.UserPermissionLinks.Clear(); invite.Organization.RemotelyUsers.Add(user); RemotelyContext.SaveChanges(); RemotelyContext.InviteLinks.Remove(invite); RemotelyContext.SaveChanges(); return true; } internal void RemoveUserFromOrganization(string requesterUserName, string targetUserID) { var requester = RemotelyContext.Users .Include(x => x.Organization) .ThenInclude(x => x.RemotelyUsers) .FirstOrDefault(x => x.UserName == requesterUserName); var target = requester.Organization.RemotelyUsers.FirstOrDefault(x => x.Id == targetUserID); var newOrganization = new Organization(); target.Organization = newOrganization; RemotelyContext.Organizations.Add(newOrganization); RemotelyContext.SaveChanges(); } internal void RemovePermissionFromDevices(string userID, string[] deviceIDs, string groupName) { var user = RemotelyContext.Users .Include(x => x.Organization) .ThenInclude(x => x.Devices) .FirstOrDefault(x => x.Id == userID); var group = user.Organization.PermissionGroups.FirstOrDefault(x => x.Name.ToLower() == groupName.ToLower()); foreach (var deviceID in deviceIDs) { if (user.Organization.Devices.Any(x => x.ID == deviceID)) { var device = RemotelyContext.Devices .Include(x => x.DevicePermissionLinks) .FirstOrDefault(x => x.ID == deviceID); foreach (var permission in device.DevicePermissionLinks.ToList().Where(x => x.PermissionGroupID == group.ID)) { device.DevicePermissionLinks.Remove(permission); } RemotelyContext.Entry(device).State = EntityState.Modified; } } RemotelyContext.SaveChanges(); } internal void RemovePermissionFromUser(string requesterUserName, string targetUserID, string permissionID) { var requester = RemotelyContext.Users .Include(x => x.Organization) .ThenInclude(x => x.RemotelyUsers) .ThenInclude(x => x.UserPermissionLinks) .FirstOrDefault(x => x.UserName == requesterUserName); var target = requester.Organization.RemotelyUsers.FirstOrDefault(x => x.Id == targetUserID); foreach (var permission in target.UserPermissionLinks.ToList().Where(x=>x.PermissionGroupID == permissionID)) { target.UserPermissionLinks.Remove(permission); } RemotelyContext.Entry(target).State = EntityState.Modified; RemotelyContext.SaveChanges(); } internal void SetServerVerificationToken(string deviceID, string verificationToken) { var device = RemotelyContext.Devices.Find(deviceID); if (device != null) { device.ServerVerificationToken = verificationToken; RemotelyContext.SaveChanges(); } } internal void UpdateOrganizationName(string userName, string organizationName) { RemotelyContext.Users .Include(x => x.Organization) .FirstOrDefault(x => x.UserName == userName) .Organization .OrganizationName = organizationName; RemotelyContext.SaveChanges(); } internal void UpdateTags(string deviceID, string tag) { RemotelyContext.Devices.Find(deviceID).Tags = tag; RemotelyContext.SaveChanges(); } internal void UpdateUserOptions(string userName, RemotelyUserOptions options) { RemotelyContext.Users.FirstOrDefault(x => x.UserName == userName).UserOptions = options; RemotelyContext.SaveChanges(); } } }