diff --git a/Moonlight/App/Configuration/ConfigV1.cs b/Moonlight/App/Configuration/ConfigV1.cs index b6709c8..15c6340 100644 --- a/Moonlight/App/Configuration/ConfigV1.cs +++ b/Moonlight/App/Configuration/ConfigV1.cs @@ -290,10 +290,15 @@ public class ConfigV1 public class SecurityData { [JsonProperty("Token")] - [Description("This is the moonlight app token. It is used to encrypt and decrypt data and validte tokens and sessions")] + [Description("This is the moonlight app token. It is used to encrypt and decrypt data and validate tokens and sessions")] [Blur] public string Token { get; set; } = Guid.NewGuid().ToString(); + [JsonProperty("MalwareCheckOnStart")] + [Description( + "This option will enable the scanning for malware on every server before it has been started and if something has been found, the power action will be canceled")] + public bool MalwareCheckOnStart { get; set; } = true; + [JsonProperty("BlockIpDuration")] [Description("The duration in minutes a ip will be blocked by the anti ddos system")] public int BlockIpDuration { get; set; } = 15; diff --git a/Moonlight/App/MalwareScans/FakePlayerPluginScan.cs b/Moonlight/App/MalwareScans/FakePlayerPluginScan.cs new file mode 100644 index 0000000..926c281 --- /dev/null +++ b/Moonlight/App/MalwareScans/FakePlayerPluginScan.cs @@ -0,0 +1,42 @@ +using Moonlight.App.Database.Entities; +using Moonlight.App.Models.Misc; +using Moonlight.App.Services; + +namespace Moonlight.App.MalwareScans; + +public class FakePlayerPluginScan : MalwareScan +{ + public override string Name => "Fake player plugin scan"; + public override string Description => "This scan is a simple fake player plugin scan provided by moonlight"; + + public override async Task Scan(Server server, IServiceProvider serviceProvider) + { + var serverService = serviceProvider.GetRequiredService(); + var access = await serverService.CreateFileAccess(server, null!); + var fileElements = await access.Ls(); + + if (fileElements.Any(x => !x.IsFile && x.Name == "plugins")) // Check for plugins folder + { + await access.Cd("plugins"); + fileElements = await access.Ls(); + + foreach (var fileElement in fileElements) + { + if (fileElement.Name.ToLower().Contains("fakeplayer")) + { + return new[] + { + new MalwareScanResult + { + Title = "Fake player plugin", + Description = $"Suspicious plugin file: {fileElement.Name}", + Author = "Marcel Baumgartner" + } + }; + } + } + } + + return Array.Empty(); + } +} \ No newline at end of file diff --git a/Moonlight/App/MalwareScans/MinerJarScan.cs b/Moonlight/App/MalwareScans/MinerJarScan.cs new file mode 100644 index 0000000..ea8ef3b --- /dev/null +++ b/Moonlight/App/MalwareScans/MinerJarScan.cs @@ -0,0 +1,40 @@ +using Moonlight.App.Database.Entities; +using Moonlight.App.Models.Misc; +using Moonlight.App.Services; + +namespace Moonlight.App.MalwareScans; + +public class MinerJarScan : MalwareScan +{ + public override string Name => "Miner jar scan"; + public override string Description => "This scan is a simple miner jar scan provided by moonlight"; + + public override async Task Scan(Server server, IServiceProvider serviceProvider) + { + var serverService = serviceProvider.GetRequiredService(); + var access = await serverService.CreateFileAccess(server, null!); + var fileElements = await access.Ls(); + + if (fileElements.Any(x => x.Name == "libraries" && !x.IsFile)) + { + await access.Cd("libraries"); + + fileElements = await access.Ls(); + + if (fileElements.Any(x => x.Name == "jdk" && !x.IsFile)) + { + return new[] + { + new MalwareScanResult + { + Title = "Found Miner", + Description = "Detected suspicious library directory which may contain a script for miners", + Author = "Marcel Baumgartner" + } + }; + } + } + + return Array.Empty(); + } +} \ No newline at end of file diff --git a/Moonlight/App/MalwareScans/SelfBotCodeScan.cs b/Moonlight/App/MalwareScans/SelfBotCodeScan.cs new file mode 100644 index 0000000..3c0a770 --- /dev/null +++ b/Moonlight/App/MalwareScans/SelfBotCodeScan.cs @@ -0,0 +1,38 @@ +using Moonlight.App.Database.Entities; +using Moonlight.App.Models.Misc; +using Moonlight.App.Services; + +namespace Moonlight.App.MalwareScans; + +public class SelfBotCodeScan : MalwareScan +{ + public override string Name => "Selfbot code scan"; + public override string Description => "This scan is a simple selfbot code scan provided by moonlight"; + + public override async Task Scan(Server server, IServiceProvider serviceProvider) + { + var serverService = serviceProvider.GetRequiredService(); + var access = await serverService.CreateFileAccess(server, null!); + var fileElements = await access.Ls(); + + foreach (var script in fileElements.Where(x => x.Name.EndsWith(".py") && x.IsFile)) + { + var rawScript = await access.Read(script); + + if (rawScript.Contains("https://discord.com/api") && !rawScript.Contains("https://discord.com/api/oauth2") && !rawScript.Contains("https://discord.com/api/webhook") || rawScript.Contains("https://rblxwild.com")) //TODO: Export to plugins, add regex for checking + { + return new[] + { + new MalwareScanResult + { + Title = "Potential selfbot", + Description = $"Suspicious script file: {script.Name}", + Author = "Marcel Baumgartner" + } + }; + } + } + + return Array.Empty(); + } +} \ No newline at end of file diff --git a/Moonlight/App/MalwareScans/SelfBotScan.cs b/Moonlight/App/MalwareScans/SelfBotScan.cs new file mode 100644 index 0000000..963017e --- /dev/null +++ b/Moonlight/App/MalwareScans/SelfBotScan.cs @@ -0,0 +1,33 @@ +using Moonlight.App.Database.Entities; +using Moonlight.App.Models.Misc; +using Moonlight.App.Services; + +namespace Moonlight.App.MalwareScans; + +public class SelfBotScan : MalwareScan +{ + public override string Name => "Selfbot Scan"; + public override string Description => "This scan is a simple selfbot scan provided by moonlight"; + + public override async Task Scan(Server server, IServiceProvider serviceProvider) + { + var serverService = serviceProvider.GetRequiredService(); + var access = await serverService.CreateFileAccess(server, null!); + var fileElements = await access.Ls(); + + if (fileElements.Any(x => x.Name == "tokens.txt")) + { + return new[] + { + new MalwareScanResult + { + Title = "Found SelfBot", + Description = "Detected suspicious 'tokens.txt' file which may contain tokens for a selfbot", + Author = "Marcel Baumgartner" + } + }; + } + + return Array.Empty(); + } +} \ No newline at end of file diff --git a/Moonlight/App/Models/Misc/MalwareScan.cs b/Moonlight/App/Models/Misc/MalwareScan.cs new file mode 100644 index 0000000..9ca1865 --- /dev/null +++ b/Moonlight/App/Models/Misc/MalwareScan.cs @@ -0,0 +1,10 @@ +using Moonlight.App.Database.Entities; + +namespace Moonlight.App.Models.Misc; + +public abstract class MalwareScan +{ + public abstract string Name { get; } + public abstract string Description { get; } + public abstract Task Scan(Server server, IServiceProvider serviceProvider); +} \ No newline at end of file diff --git a/Moonlight/App/Models/Misc/MalwareScanResult.cs b/Moonlight/App/Models/Misc/MalwareScanResult.cs index 41ba334..4f78885 100644 --- a/Moonlight/App/Models/Misc/MalwareScanResult.cs +++ b/Moonlight/App/Models/Misc/MalwareScanResult.cs @@ -2,7 +2,7 @@ public class MalwareScanResult { - public string Title { get; set; } = ""; + public string Title { get; set; } public string Description { get; set; } = ""; public string Author { get; set; } = ""; } \ No newline at end of file diff --git a/Moonlight/App/Plugin/MoonlightPlugin.cs b/Moonlight/App/Plugin/MoonlightPlugin.cs index 875c33e..15fcf48 100644 --- a/Moonlight/App/Plugin/MoonlightPlugin.cs +++ b/Moonlight/App/Plugin/MoonlightPlugin.cs @@ -1,4 +1,5 @@ -using Moonlight.App.Plugin.UI.Servers; +using Moonlight.App.Models.Misc; +using Moonlight.App.Plugin.UI.Servers; using Moonlight.App.Plugin.UI.Webspaces; namespace Moonlight.App.Plugin; @@ -12,4 +13,5 @@ public abstract class MoonlightPlugin public Func? OnBuildServerPage { get; set; } public Func? OnBuildWebspacePage { get; set; } public Func? OnBuildServices { get; set; } + public Func, Task>>? OnBuildMalwareScans { get; set; } } \ No newline at end of file diff --git a/Moonlight/App/Services/Background/MalwareBackgroundScanService.cs b/Moonlight/App/Services/Background/MalwareBackgroundScanService.cs new file mode 100644 index 0000000..dcf975a --- /dev/null +++ b/Moonlight/App/Services/Background/MalwareBackgroundScanService.cs @@ -0,0 +1,148 @@ +using Moonlight.App.ApiClients.Daemon.Resources; +using Moonlight.App.Database.Entities; +using Moonlight.App.Events; +using Moonlight.App.Exceptions; +using Moonlight.App.Helpers; +using Moonlight.App.Models.Misc; +using Moonlight.App.Repositories; + +namespace Moonlight.App.Services.Background; + +public class MalwareBackgroundScanService +{ + private readonly EventSystem Event; + private readonly IServiceScopeFactory ServiceScopeFactory; + + public bool IsRunning => !ScanTask?.IsCompleted ?? false; + public bool ScanAllServers { get; set; } + public readonly Dictionary ScanResults; + public string Status { get; private set; } = "N/A"; + + private Task? ScanTask; + + public MalwareBackgroundScanService(IServiceScopeFactory serviceScopeFactory, EventSystem eventSystem) + { + ServiceScopeFactory = serviceScopeFactory; + Event = eventSystem; + ScanResults = new(); + } + + public Task Start() + { + if (IsRunning) + throw new DisplayException("Malware scan is already running"); + + ScanTask = Task.Run(Run); + + return Task.CompletedTask; + } + + private async Task Run() + { + // Clean results + Status = "Clearing last results"; + await Event.Emit("malwareScan.status", IsRunning); + + lock (ScanResults) + ScanResults.Clear(); + + await Event.Emit("malwareScan.result"); + + using var scope = ServiceScopeFactory.CreateScope(); + var serverRepo = scope.ServiceProvider.GetRequiredService>(); + var malwareScanService = scope.ServiceProvider.GetRequiredService(); + + Status = "Fetching servers to scan"; + await Event.Emit("malwareScan.status", IsRunning); + + Server[] servers; + + if (ScanAllServers) + servers = serverRepo.Get().ToArray(); + else + servers = await GetOnlineServers(); + + // Perform scan + + int i = 1; + foreach (var server in servers) + { + Status = $"[{i} / {servers.Length}] Scanning server {server.Name}"; + await Event.Emit("malwareScan.status", IsRunning); + + var results = await malwareScanService.Perform(server); + + if (results.Any()) + { + lock (ScanResults) + { + ScanResults.Add(server, results); + } + + await Event.Emit("malwareScan.result"); + } + + i++; + } + + Task.Run(async () => // Because we use the task as the status indicator we need to notify the event system in a new task + { + await Task.Delay(TimeSpan.FromSeconds(5)); + await Event.Emit("malwareScan.status", IsRunning); + }); + } + + private async Task GetOnlineServers() + { + using var scope = ServiceScopeFactory.CreateScope(); + + // Load services from di scope + var nodeRepo = scope.ServiceProvider.GetRequiredService>(); + var serverRepo = scope.ServiceProvider.GetRequiredService>(); + var nodeService = scope.ServiceProvider.GetRequiredService(); + + var nodes = nodeRepo.Get().ToArray(); + var containers = new List(); + + // Fetch and summarize all running containers from all nodes + Logger.Verbose("Fetching and summarizing all running containers from all nodes"); + + Status = "Fetching and summarizing all running containers from all nodes"; + await Event.Emit("malwareScan.status", IsRunning); + + foreach (var node in nodes) + { + var metrics = await nodeService.GetDockerMetrics(node); + + foreach (var container in metrics.Containers) + { + containers.Add(container); + } + } + + var containerServerMapped = new Dictionary(); + + // Map all the containers to their corresponding server if existing + Logger.Verbose("Mapping all the containers to their corresponding server if existing"); + + Status = "Mapping all the containers to their corresponding server if existing"; + await Event.Emit("malwareScan.status", IsRunning); + + foreach (var container in containers) + { + if (Guid.TryParse(container.Name, out Guid uuid)) + { + var server = serverRepo + .Get() + .FirstOrDefault(x => x.Uuid == uuid); + + if(server == null) + continue; + + containerServerMapped.Add(server, container); + } + } + + return containerServerMapped.Keys.ToArray(); + } +} \ No newline at end of file diff --git a/Moonlight/App/Services/Background/MalwareScanService.cs b/Moonlight/App/Services/Background/MalwareScanService.cs deleted file mode 100644 index 989b4a8..0000000 --- a/Moonlight/App/Services/Background/MalwareScanService.cs +++ /dev/null @@ -1,238 +0,0 @@ -using Moonlight.App.ApiClients.Daemon.Resources; -using Moonlight.App.Database.Entities; -using Moonlight.App.Events; -using Moonlight.App.Exceptions; -using Moonlight.App.Helpers; -using Moonlight.App.Models.Misc; -using Moonlight.App.Repositories; - -namespace Moonlight.App.Services.Background; - -public class MalwareScanService -{ - private Repository ServerRepository; - private Repository NodeRepository; - private NodeService NodeService; - private ServerService ServerService; - - private readonly EventSystem Event; - private readonly IServiceScopeFactory ServiceScopeFactory; - - public bool IsRunning { get; private set; } - public bool ScanAllServers { get; set; } - public readonly Dictionary ScanResults; - public string Status { get; private set; } = "N/A"; - - public MalwareScanService(IServiceScopeFactory serviceScopeFactory, EventSystem eventSystem) - { - ServiceScopeFactory = serviceScopeFactory; - Event = eventSystem; - ScanResults = new(); - } - - public Task Start() - { - if (IsRunning) - throw new DisplayException("Malware scan is already running"); - - Task.Run(Run); - - return Task.CompletedTask; - } - - private async Task Run() - { - // Clean results - IsRunning = true; - Status = "Clearing last results"; - await Event.Emit("malwareScan.status", IsRunning); - - lock (ScanResults) - { - ScanResults.Clear(); - } - - await Event.Emit("malwareScan.result"); - - // Load servers to scan - - using var scope = ServiceScopeFactory.CreateScope(); - - // Load services from di scope - NodeRepository = scope.ServiceProvider.GetRequiredService>(); - ServerRepository = scope.ServiceProvider.GetRequiredService>(); - NodeService = scope.ServiceProvider.GetRequiredService(); - ServerService = scope.ServiceProvider.GetRequiredService(); - - Status = "Fetching servers to scan"; - await Event.Emit("malwareScan.status", IsRunning); - - Server[] servers; - - if (ScanAllServers) - servers = ServerRepository.Get().ToArray(); - else - servers = await GetOnlineServers(); - - // Perform scan - - int i = 1; - foreach (var server in servers) - { - Status = $"[{i} / {servers.Length}] Scanning server {server.Name}"; - await Event.Emit("malwareScan.status", IsRunning); - - var results = await PerformScanOnServer(server); - - if (results.Any()) - { - lock (ScanResults) - { - ScanResults.Add(server, results); - } - - await Event.Emit("malwareScan.result"); - } - - i++; - } - - IsRunning = false; - await Event.Emit("malwareScan.status", IsRunning); - } - - private async Task GetOnlineServers() - { - using var scope = ServiceScopeFactory.CreateScope(); - - // Load services from di scope - NodeRepository = scope.ServiceProvider.GetRequiredService>(); - ServerRepository = scope.ServiceProvider.GetRequiredService>(); - NodeService = scope.ServiceProvider.GetRequiredService(); - ServerService = scope.ServiceProvider.GetRequiredService(); - - var nodes = NodeRepository.Get().ToArray(); - var containers = new List(); - - // Fetch and summarize all running containers from all nodes - Logger.Verbose("Fetching and summarizing all running containers from all nodes"); - - Status = "Fetching and summarizing all running containers from all nodes"; - await Event.Emit("malwareScan.status", IsRunning); - - foreach (var node in nodes) - { - var metrics = await NodeService.GetDockerMetrics(node); - - foreach (var container in metrics.Containers) - { - containers.Add(container); - } - } - - var containerServerMapped = new Dictionary(); - - // Map all the containers to their corresponding server if existing - Logger.Verbose("Mapping all the containers to their corresponding server if existing"); - - Status = "Mapping all the containers to their corresponding server if existing"; - await Event.Emit("malwareScan.status", IsRunning); - - foreach (var container in containers) - { - if (Guid.TryParse(container.Name, out Guid uuid)) - { - var server = ServerRepository - .Get() - .FirstOrDefault(x => x.Uuid == uuid); - - if(server == null) - continue; - - containerServerMapped.Add(server, container); - } - } - - return containerServerMapped.Keys.ToArray(); - } - - private async Task PerformScanOnServer(Server server) - { - var results = new List(); - - // TODO: Move scans to an universal format / api - - // Define scans here - - async Task ScanSelfBot() - { - var access = await ServerService.CreateFileAccess(server, null!); - var fileElements = await access.Ls(); - - if (fileElements.Any(x => x.Name == "tokens.txt")) - { - results.Add(new () - { - Title = "Found SelfBot", - Description = "Detected suspicious 'tokens.txt' file which may contain tokens for a selfbot", - Author = "Marcel Baumgartner" - }); - } - } - - async Task ScanMinerJar() - { - var access = await ServerService.CreateFileAccess(server, null!); - var fileElements = await access.Ls(); - - if (fileElements.Any(x => x.Name == "libraries" && !x.IsFile)) - { - await access.Cd("libraries"); - - fileElements = await access.Ls(); - - if (fileElements.Any(x => x.Name == "jdk" && !x.IsFile)) - { - results.Add(new () - { - Title = "Found Miner", - Description = "Detected suspicious library directory which may contain a script for miners", - Author = "Marcel Baumgartner" - }); - } - } - } - - async Task ScanFakePlayerPlugins() - { - var access = await ServerService.CreateFileAccess(server, null!); - var fileElements = await access.Ls(); - - if (fileElements.Any(x => !x.IsFile && x.Name == "plugins")) // Check for plugins folder - { - await access.Cd("plugins"); - fileElements = await access.Ls(); - - foreach (var fileElement in fileElements) - { - if (fileElement.Name.ToLower().Contains("fake")) - { - results.Add(new() - { - Title = "Fake player plugin", - Description = $"Suspicious plugin file: {fileElement.Name}", - Author = "Marcel Baumgartner" - }); - } - } - } - } - - // Execute scans - await ScanSelfBot(); - await ScanFakePlayerPlugins(); - await ScanMinerJar(); - - return results.ToArray(); - } -} \ No newline at end of file diff --git a/Moonlight/App/Services/MalwareScanService.cs b/Moonlight/App/Services/MalwareScanService.cs new file mode 100644 index 0000000..08dbaab --- /dev/null +++ b/Moonlight/App/Services/MalwareScanService.cs @@ -0,0 +1,49 @@ +using Moonlight.App.Database.Entities; +using Moonlight.App.MalwareScans; +using Moonlight.App.Models.Misc; +using Moonlight.App.Services.Plugins; + +namespace Moonlight.App.Services; + +public class MalwareScanService //TODO: Make this moddable using plugins +{ + private readonly PluginService PluginService; + private readonly IServiceScopeFactory ServiceScopeFactory; + + public MalwareScanService(PluginService pluginService, IServiceScopeFactory serviceScopeFactory) + { + PluginService = pluginService; + ServiceScopeFactory = serviceScopeFactory; + } + + public async Task Perform(Server server) + { + var defaultScans = new List + { + new SelfBotScan(), + new MinerJarScan(), + new SelfBotCodeScan(), + new FakePlayerPluginScan() + }; + + var scans = await PluginService.BuildMalwareScans(defaultScans.ToArray()); + + var results = new List(); + using var scope = ServiceScopeFactory.CreateScope(); + + foreach (var scan in scans) + { + var result = await scan.Scan(server, scope.ServiceProvider); + + if (result.Any()) + { + foreach (var scanResult in result) + { + results.Add(scanResult); + } + } + } + + return results.ToArray(); + } +} \ No newline at end of file diff --git a/Moonlight/App/Services/Plugins/PluginService.cs b/Moonlight/App/Services/Plugins/PluginService.cs index 641f658..2bbeb6e 100644 --- a/Moonlight/App/Services/Plugins/PluginService.cs +++ b/Moonlight/App/Services/Plugins/PluginService.cs @@ -1,6 +1,7 @@ using System.Reflection; using System.Runtime.Loader; using Moonlight.App.Helpers; +using Moonlight.App.Models.Misc; using Moonlight.App.Plugin; using Moonlight.App.Plugin.UI.Servers; using Moonlight.App.Plugin.UI.Webspaces; @@ -97,4 +98,17 @@ public class PluginService await plugin.OnBuildServices.Invoke(serviceCollection); } } + + public async Task BuildMalwareScans(MalwareScan[] defaultScans) + { + var scanList = defaultScans.ToList(); + + foreach (var plugin in Plugins) + { + if (plugin.OnBuildMalwareScans != null) + scanList = await plugin.OnBuildMalwareScans.Invoke(scanList); + } + + return scanList.ToArray(); + } } \ No newline at end of file diff --git a/Moonlight/App/Services/ServerService.cs b/Moonlight/App/Services/ServerService.cs index 30d8318..7e9876d 100644 --- a/Moonlight/App/Services/ServerService.cs +++ b/Moonlight/App/Services/ServerService.cs @@ -12,6 +12,8 @@ using Moonlight.App.Helpers.Wings; using Moonlight.App.Models.Misc; using Moonlight.App.Repositories; using Moonlight.App.Repositories.Servers; +using Moonlight.App.Services.Background; +using Moonlight.App.Services.Plugins; using FileAccess = Moonlight.App.Helpers.Files.FileAccess; namespace Moonlight.App.Services; @@ -32,6 +34,11 @@ public class ServerService private readonly DateTimeService DateTimeService; private readonly EventSystem Event; + // We inject the dependencies for the malware scan service here because otherwise it may result in + // a circular dependency injection which will crash the app + private readonly PluginService PluginService; + private readonly IServiceScopeFactory ServiceScopeFactory; + public ServerService( ServerRepository serverRepository, WingsApiHelper wingsApiHelper, @@ -45,7 +52,9 @@ public class ServerService NodeAllocationRepository nodeAllocationRepository, DateTimeService dateTimeService, EventSystem eventSystem, - Repository serverVariablesRepository) + Repository serverVariablesRepository, + PluginService pluginService, + IServiceScopeFactory serviceScopeFactory) { ServerRepository = serverRepository; WingsApiHelper = wingsApiHelper; @@ -60,6 +69,8 @@ public class ServerService DateTimeService = dateTimeService; Event = eventSystem; ServerVariablesRepository = serverVariablesRepository; + PluginService = pluginService; + ServiceScopeFactory = serviceScopeFactory; } private Server EnsureNodeData(Server s) @@ -99,6 +110,26 @@ public class ServerService { Server server = EnsureNodeData(s); + if (ConfigService.Get().Moonlight.Security.MalwareCheckOnStart && signal == PowerSignal.Start || + signal == PowerSignal.Restart) + { + var results = await new MalwareScanService( + PluginService, + ServiceScopeFactory + ).Perform(server); + + if (results.Any()) + { + var resultText = string.Join(" ", results.Select(x => x.Title)); + + Logger.Warn($"Found malware on server {server.Uuid}. Results: " + resultText); + + throw new DisplayException( + $"Unable to start server. Found following malware on this server: {resultText}. Please contact the support if you think this detection is a false positive", + true); + } + } + var rawSignal = signal.ToString().ToLower(); await WingsApiHelper.Post(server.Node, $"api/servers/{server.Uuid}/power", new ServerPower() @@ -420,10 +451,7 @@ public class ServerService await new Retry() .Times(3) .At(x => x.Message.Contains("A task was canceled")) - .Call(async () => - { - await WingsApiHelper.Delete(server.Node, $"api/servers/{server.Uuid}", null); - }); + .Call(async () => { await WingsApiHelper.Delete(server.Node, $"api/servers/{server.Uuid}", null); }); } catch (WingsException e) { diff --git a/Moonlight/Program.cs b/Moonlight/Program.cs index 541028d..05f6d54 100644 --- a/Moonlight/Program.cs +++ b/Moonlight/Program.cs @@ -217,6 +217,7 @@ namespace Moonlight builder.Services.AddSingleton(); builder.Services.AddScoped(); builder.Services.AddScoped(); + builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddSingleton(); @@ -245,7 +246,7 @@ namespace Moonlight builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); - builder.Services.AddSingleton(); + builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); @@ -297,7 +298,7 @@ namespace Moonlight _ = app.Services.GetRequiredService(); _ = app.Services.GetRequiredService(); _ = app.Services.GetRequiredService(); - _ = app.Services.GetRequiredService(); + _ = app.Services.GetRequiredService(); _ = app.Services.GetRequiredService(); _ = app.Services.GetRequiredService(); _ = app.Services.GetRequiredService(); diff --git a/Moonlight/Shared/Views/Admin/Security/Malware.razor b/Moonlight/Shared/Views/Admin/Security/Malware.razor index 195ef0b..bb4a2a6 100644 --- a/Moonlight/Shared/Views/Admin/Security/Malware.razor +++ b/Moonlight/Shared/Views/Admin/Security/Malware.razor @@ -8,7 +8,7 @@ @using Moonlight.App.Events @using Moonlight.App.Models.Misc -@inject MalwareScanService MalwareScanService +@inject MalwareBackgroundScanService MalwareBackgroundScanService @inject SmartTranslateService SmartTranslateService @inject EventSystem Event @@ -22,15 +22,15 @@
- @if (MalwareScanService.IsRunning) + @if (MalwareBackgroundScanService.IsRunning) { } - @(MalwareScanService.Status) + @(MalwareBackgroundScanService.Status)