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; using Remotely.Shared.ViewModels.Organization; namespace Remotely.Server.Data { public class DataService { public DataService(ApplicationDbContext context, ApplicationConfig appConfig) { RemotelyContext = context; AppConfig = appConfig; } private ApplicationConfig AppConfig { get; set; } private ApplicationDbContext RemotelyContext { get; set; } public 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, ResetUrl = invite.ResetUrl }; requester.Organization.InviteLinks.Add(newInvite); RemotelyContext.SaveChanges(); return newInvite; } 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, out Device updatedDevice) { device.LastOnline = DateTime.Now; var existingDevice = RemotelyContext.Devices.Find(device.ID); if (existingDevice != null) { existingDevice.CurrentUser = device.CurrentUser; existingDevice.DeviceName = device.DeviceName; existingDevice.Drives = device.Drives; existingDevice.FreeMemory = device.FreeMemory; existingDevice.FreeStorage = device.FreeStorage; existingDevice.Is64Bit = device.Is64Bit; existingDevice.IsOnline = true; existingDevice.OSArchitecture = device.OSArchitecture; existingDevice.OSDescription = device.OSDescription; existingDevice.Platform = device.Platform; existingDevice.ProcessorCount = device.ProcessorCount; existingDevice.TotalMemory = device.TotalMemory; existingDevice.TotalStorage = device.TotalStorage; existingDevice.AgentVersion = device.AgentVersion; updatedDevice = existingDevice; } else { updatedDevice = device; 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 string AddSharedFile(IFormFile file, string organizationID) { var expirationDate = DateTime.Now.AddDays(-AppConfig.DataRetentionInDays); var expiredFiles = RemotelyContext.SharedFiles.Where(x => x.Timestamp < expirationDate); RemotelyContext.RemoveRange(expiredFiles); 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, OrganizationID = organizationID }); RemotelyContext.SaveChanges(); return newEntity.Entity.ID; } public 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(); } public void CleanupOldRecords() { if (AppConfig.DataRetentionInDays > 0) { var expirationDate = DateTime.Now - TimeSpan.FromDays(AppConfig.DataRetentionInDays); var eventLogs = RemotelyContext.EventLogs .Where(x => x.TimeStamp < expirationDate); RemotelyContext.RemoveRange(eventLogs); var commandContexts = RemotelyContext.CommandContexts .Where(x => x.TimeStamp < expirationDate); RemotelyContext.RemoveRange(commandContexts); var sharedFiles = RemotelyContext.SharedFiles .Where(x => x.Timestamp < expirationDate); RemotelyContext.RemoveRange(sharedFiles); RemotelyContext.SaveChanges(); } } public 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); var user = RemotelyContext.Users.FirstOrDefault(x => x.UserName == invite.InvitedUser); if (user != null && string.IsNullOrWhiteSpace(user.PasswordHash)) { RemotelyContext.Remove(user); } RemotelyContext.Remove(invite); RemotelyContext.SaveChanges(); } public void DeviceDisconnected(string deviceID) { var device = RemotelyContext.Devices.Find(deviceID); if (device != null) { device.LastOnline = DateTime.Now; device.IsOnline = false; 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 .FirstOrDefault(x => x.ID == deviceID && x.OrganizationID == remotelyUser.OrganizationID); return RemotelyContext.Devices.Any(x => x.ID == deviceID && x.OrganizationID == remotelyUser.OrganizationID); } public bool DoesUserHaveAccessToDevice(string deviceID, string remotelyUserID) { var remotelyUser = RemotelyContext.Users.Find(remotelyUserID); return RemotelyContext.Devices.Any(x => x.ID == deviceID && x.OrganizationID == remotelyUser.OrganizationID); } public string[] FilterDeviceIDsByUserPermission(string[] deviceIDs, RemotelyUser remotelyUser) { return RemotelyContext.Devices.Where(x => deviceIDs.Contains(x.ID) && x.OrganizationID == remotelyUser.OrganizationID ) .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.FirstOrDefault(x => x.Id == userID); return RemotelyContext.Devices.Where(x => x.OrganizationID == user.OrganizationID); } public ICollection GetAllInviteLinks(string userName) { return RemotelyContext.Users .Include(x => x.Organization) .ThenInclude(x => x.InviteLinks) .FirstOrDefault(x => x.UserName == userName) .Organization .InviteLinks; } public IEnumerable GetAllUsers(string userName) { return RemotelyContext.Users .Include(x => x.Organization) .ThenInclude(x => x.RemotelyUsers) .FirstOrDefault(x => x.UserName == userName) .Organization .RemotelyUsers; } 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.FirstOrDefault(x => x.Id == userID); return RemotelyContext.Devices.FirstOrDefault(x => x.OrganizationID == user.OrganizationID && x.ID == deviceID); } public List GetDeviceGroupsForUserName(string username) { var user = RemotelyContext.Users.FirstOrDefault(x => x.UserName == username); return RemotelyContext.DeviceGroups.Where(x => x.OrganizationID == user.OrganizationID).ToList(); } public int GetOrganizationCount() { return RemotelyContext.Organizations.Count(); } public string GetOrganizationName(string userName) { return RemotelyContext.Users .Include(x => x.Organization) .FirstOrDefault(x => x.UserName == userName) .Organization .OrganizationName; } public SharedFile GetSharedFiled(string fileID) { return RemotelyContext.SharedFiles.Find(fileID); } 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 RemotelyUserOptions GetUserOptions(string userName) { return RemotelyContext.Users .FirstOrDefault(x => x.UserName == userName) .UserOptions; } public List GetUsersWithAccessToDevice(IEnumerable userIDs, Device device) { var targetDevice = RemotelyContext.Devices .FirstOrDefault(x => x.ID == device.ID && x.OrganizationID == device.OrganizationID); var targetUsers = RemotelyContext.Users.Where(x => x.OrganizationID == device.OrganizationID && userIDs.Contains(x.Id)).ToList(); return targetUsers.ToList(); } public 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) .FirstOrDefault(x => x.UserName == userName); user.Organization = invite.Organization; user.OrganizationID = invite.Organization.ID; user.IsAdministrator = invite.IsAdmin; invite.Organization.RemotelyUsers.Add(user); RemotelyContext.SaveChanges(); RemotelyContext.InviteLinks.Remove(invite); RemotelyContext.SaveChanges(); return true; } public void RemoveDevices(string[] deviceIDs) { var devices = RemotelyContext.Devices .Where(x => deviceIDs.Contains(x.ID)); RemotelyContext.Devices.RemoveRange(devices); RemotelyContext.SaveChanges(); } public 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(); } public void SetAllDevicesNotOnline() { RemotelyContext.Devices.ForEachAsync(x => { x.IsOnline = false; }).Wait(); RemotelyContext.SaveChanges(); } public void SetServerVerificationToken(string deviceID, string verificationToken) { var device = RemotelyContext.Devices.Find(deviceID); if (device != null) { device.ServerVerificationToken = verificationToken; RemotelyContext.SaveChanges(); } } public void UpdateDevice(string deviceID, string tag = null, string alias = null, string deviceGroupID = null) { var device = RemotelyContext.Devices.Find(deviceID); if (device == null) { return; } device.Tags = tag ?? device.Tags; device.DeviceGroupID = deviceGroupID ?? device.DeviceGroupID; device.Alias = alias ?? device.Alias; RemotelyContext.SaveChanges(); } public void UpdateOrganizationName(string userName, string organizationName) { RemotelyContext.Users .Include(x => x.Organization) .FirstOrDefault(x => x.UserName == userName) .Organization .OrganizationName = organizationName; RemotelyContext.SaveChanges(); } public void UpdateUserOptions(string userName, RemotelyUserOptions options) { RemotelyContext.Users.FirstOrDefault(x => x.UserName == userName).UserOptions = options; 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(); } } }