diff --git a/.idea/.idea.MalwareMultiScan/.idea/runConfigurations/MalwareMultiScan_Worker_Dockerfile.xml b/.idea/.idea.MalwareMultiScan/.idea/runConfigurations/MalwareMultiScan_Scanner_Dockerfile.xml similarity index 72% rename from .idea/.idea.MalwareMultiScan/.idea/runConfigurations/MalwareMultiScan_Worker_Dockerfile.xml rename to .idea/.idea.MalwareMultiScan/.idea/runConfigurations/MalwareMultiScan_Scanner_Dockerfile.xml index 5c2be23..5a37aed 100644 --- a/.idea/.idea.MalwareMultiScan/.idea/runConfigurations/MalwareMultiScan_Worker_Dockerfile.xml +++ b/.idea/.idea.MalwareMultiScan/.idea/runConfigurations/MalwareMultiScan_Scanner_Dockerfile.xml @@ -1,5 +1,5 @@ - + diff --git a/MalwareMultiScan.Api/Attributes/HttpUrlValidationAttribute.cs b/MalwareMultiScan.Api/Attributes/IsHttpUrlAttribute.cs similarity index 51% rename from MalwareMultiScan.Api/Attributes/HttpUrlValidationAttribute.cs rename to MalwareMultiScan.Api/Attributes/IsHttpUrlAttribute.cs index feef5c4..cda488e 100644 --- a/MalwareMultiScan.Api/Attributes/HttpUrlValidationAttribute.cs +++ b/MalwareMultiScan.Api/Attributes/IsHttpUrlAttribute.cs @@ -3,13 +3,17 @@ using System.ComponentModel.DataAnnotations; namespace MalwareMultiScan.Api.Attributes { - public class HttpUrlValidationAttribute : ValidationAttribute + /// + /// Validate URI to be an absolute http(s) URL. + /// + internal class IsHttpUrlAttribute : ValidationAttribute { + /// protected override ValidationResult IsValid(object value, ValidationContext validationContext) { - var uri = (Uri) value; - - if (uri == null || !uri.IsAbsoluteUri || uri.Scheme != "http" && uri.Scheme != "https") + if (!Uri.TryCreate((string)value, UriKind.Absolute, out var uri) + || !uri.IsAbsoluteUri + || uri.Scheme != "http" && uri.Scheme != "https") return new ValidationResult("Only absolute http(s) URLs are supported"); return ValidationResult.Success; diff --git a/MalwareMultiScan.Api/Attributes/MaxFileSizeAttribute.cs b/MalwareMultiScan.Api/Attributes/MaxFileSizeAttribute.cs new file mode 100644 index 0000000..56baa38 --- /dev/null +++ b/MalwareMultiScan.Api/Attributes/MaxFileSizeAttribute.cs @@ -0,0 +1,28 @@ +using System.ComponentModel.DataAnnotations; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +namespace MalwareMultiScan.Api.Attributes +{ + /// + /// Validate uploaded file size for the max file size defined in settings. + /// + public class MaxFileSizeAttribute : ValidationAttribute + { + /// + protected override ValidationResult IsValid(object value, ValidationContext validationContext) + { + var maxSize = validationContext + .GetRequiredService() + .GetValue("MaxFileSize"); + + var formFile = (IFormFile) value; + + if (formFile == null || formFile.Length > maxSize) + return new ValidationResult($"File exceeds the maximum size of {maxSize} bytes"); + + return ValidationResult.Success; + } + } +} \ No newline at end of file diff --git a/MalwareMultiScan.Api/Controllers/DownloadController.cs b/MalwareMultiScan.Api/Controllers/DownloadController.cs index ead47f3..af088da 100644 --- a/MalwareMultiScan.Api/Controllers/DownloadController.cs +++ b/MalwareMultiScan.Api/Controllers/DownloadController.cs @@ -5,7 +5,9 @@ using Microsoft.AspNetCore.Mvc; namespace MalwareMultiScan.Api.Controllers { + [ApiController] [Route("download")] + [Produces("application/octet-stream")] public class DownloadController : Controller { private readonly ScanResultService _scanResultService; diff --git a/MalwareMultiScan.Api/Controllers/QueueController.cs b/MalwareMultiScan.Api/Controllers/QueueController.cs index 3cb44ab..b27e0db 100644 --- a/MalwareMultiScan.Api/Controllers/QueueController.cs +++ b/MalwareMultiScan.Api/Controllers/QueueController.cs @@ -1,4 +1,4 @@ -using System; +using System.ComponentModel.DataAnnotations; using System.Threading.Tasks; using MalwareMultiScan.Api.Attributes; using MalwareMultiScan.Api.Data.Models; @@ -23,37 +23,33 @@ namespace MalwareMultiScan.Api.Controllers [HttpPost("file")] [ProducesResponseType(typeof(ScanResult), StatusCodes.Status201Created)] [ProducesResponseType(StatusCodes.Status400BadRequest)] - public async Task ScanFile([FromForm] IFormFile file) + public async Task ScanFile( + [Required, MaxFileSize] IFormFile file) { var result = await _scanResultService.CreateScanResult(); string storedFileId; await using (var uploadFileStream = file.OpenReadStream()) - { storedFileId = await _scanResultService.StoreFile(file.Name, uploadFileStream); - } await _scanResultService.QueueUrlScan(result, Url.Action("Index", "Download", new {id = storedFileId}, Request.Scheme, Request.Host.Value)); - return Created(Url.Action("Index", "ScanResults", new {id = result.Id}, - Request.Scheme, Request.Host.Value), result); + return CreatedAtAction("Index", "ScanResults", new {id = result.Id}, result); } [HttpPost("url")] [ProducesResponseType(typeof(ScanResult), StatusCodes.Status201Created)] [ProducesResponseType(StatusCodes.Status400BadRequest)] - public async Task ScanUrl([FromForm] [HttpUrlValidation] Uri url) + public async Task ScanUrl( + [FromForm, Required, IsHttpUrl] string url) { var result = await _scanResultService.CreateScanResult(); - var resultUrl = Url.Action("Index", "ScanResults", new {id = result.Id}, - Request.Scheme, Request.Host.Value); + await _scanResultService.QueueUrlScan(result, url); - await _scanResultService.QueueUrlScan(result, url.ToString()); - - return Created(resultUrl, result); + return CreatedAtAction("Index", "ScanResults", new {id = result.Id}, result); } } } \ No newline at end of file diff --git a/MalwareMultiScan.Api/Controllers/ScanResultsController.cs b/MalwareMultiScan.Api/Controllers/ScanResultsController.cs index 5137920..661a873 100644 --- a/MalwareMultiScan.Api/Controllers/ScanResultsController.cs +++ b/MalwareMultiScan.Api/Controllers/ScanResultsController.cs @@ -20,6 +20,7 @@ namespace MalwareMultiScan.Api.Controllers [HttpGet("{id}")] [ProducesResponseType(typeof(ScanResult), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task Index(string id) { var scanResult = await _scanResultService.GetScanResult(id); diff --git a/MalwareMultiScan.Api/Data/Configuration/ScanBackend.cs b/MalwareMultiScan.Api/Data/Configuration/ScanBackend.cs index a230136..55f369c 100644 --- a/MalwareMultiScan.Api/Data/Configuration/ScanBackend.cs +++ b/MalwareMultiScan.Api/Data/Configuration/ScanBackend.cs @@ -3,6 +3,6 @@ namespace MalwareMultiScan.Api.Data.Configuration public class ScanBackend { public string Id { get; set; } - public string Name { get; set; } + public bool Enabled { get; set; } } } \ No newline at end of file diff --git a/MalwareMultiScan.Api/Data/Models/ScanResultEntry.cs b/MalwareMultiScan.Api/Data/Models/ScanResultEntry.cs index dd3b536..a566c3d 100644 --- a/MalwareMultiScan.Api/Data/Models/ScanResultEntry.cs +++ b/MalwareMultiScan.Api/Data/Models/ScanResultEntry.cs @@ -3,7 +3,7 @@ namespace MalwareMultiScan.Api.Data.Models public class ScanResultEntry { public bool Completed { get; set; } - public bool Succeeded { get; set; } + public bool? Succeeded { get; set; } public string[] Threats { get; set; } } } \ No newline at end of file diff --git a/MalwareMultiScan.Api/Extensions/ServiceCollectionExtensions.cs b/MalwareMultiScan.Api/Extensions/ServiceCollectionExtensions.cs new file mode 100644 index 0000000..feb6a21 --- /dev/null +++ b/MalwareMultiScan.Api/Extensions/ServiceCollectionExtensions.cs @@ -0,0 +1,42 @@ +using System.Net; +using EasyNetQ; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.HttpOverrides; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using MongoDB.Driver; + +namespace MalwareMultiScan.Api.Extensions +{ + internal static class ServiceCollectionExtensions + { + public static void AddMongoDb(this IServiceCollection services, IConfiguration configuration) + { + services.AddSingleton( + serviceProvider => + { + var db = new MongoClient(configuration.GetConnectionString("Mongo")); + + return db.GetDatabase( + configuration.GetValue("DatabaseName")); + }); + } + + public static void AddRabbitMq(this IServiceCollection services, IConfiguration configuration) + { + services.AddSingleton(x => + RabbitHutch.CreateBus(configuration.GetConnectionString("RabbitMQ"))); + } + + public static void AddDockerForwardedHeadersOptions(this IServiceCollection services) + { + services.Configure(options => + { + options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto; + options.KnownNetworks.Add(new IPNetwork(IPAddress.Parse("::ffff:10.0.0.0"), 104)); + options.KnownNetworks.Add(new IPNetwork(IPAddress.Parse("::ffff:192.168.0.0"), 112)); + options.KnownNetworks.Add(new IPNetwork(IPAddress.Parse("::ffff:172.16.0.0"), 108)); + }); + } + } +} \ No newline at end of file diff --git a/MalwareMultiScan.Api/MalwareMultiScan.Api.csproj b/MalwareMultiScan.Api/MalwareMultiScan.Api.csproj index 472b337..312f84f 100644 --- a/MalwareMultiScan.Api/MalwareMultiScan.Api.csproj +++ b/MalwareMultiScan.Api/MalwareMultiScan.Api.csproj @@ -14,18 +14,10 @@ - - - <_ContentIncludedByDefault Remove="Properties\launchSettings.json" /> - - - - - diff --git a/MalwareMultiScan.Api/Program.cs b/MalwareMultiScan.Api/Program.cs index 13d0b5b..acaf861 100644 --- a/MalwareMultiScan.Api/Program.cs +++ b/MalwareMultiScan.Api/Program.cs @@ -13,7 +13,7 @@ namespace MalwareMultiScan.Api private static IHostBuilder CreateHostBuilder(string[] args) { return Host.CreateDefaultBuilder(args) - .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }); + .ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup()); } } } \ No newline at end of file diff --git a/MalwareMultiScan.Api/Services/ReceiverHostedService.cs b/MalwareMultiScan.Api/Services/ReceiverHostedService.cs index 6996d5d..9ead132 100644 --- a/MalwareMultiScan.Api/Services/ReceiverHostedService.cs +++ b/MalwareMultiScan.Api/Services/ReceiverHostedService.cs @@ -8,14 +8,24 @@ using Microsoft.Extensions.Logging; namespace MalwareMultiScan.Api.Services { + /// + /// Receiver hosted service. + /// public class ReceiverHostedService : IHostedService { private readonly IBus _bus; private readonly IConfiguration _configuration; - private readonly ScanResultService _scanResultService; private readonly ILogger _logger; + private readonly ScanResultService _scanResultService; - public ReceiverHostedService(IBus bus, IConfiguration configuration, ScanResultService scanResultService, + /// + /// Create receiver hosted service. + /// + /// Service bus. + /// Configuration. + /// Scan result service. + /// Logger. + public ReceiverHostedService(IBus bus, IConfiguration configuration, ScanResultService scanResultService, ILogger logger) { _bus = bus; @@ -24,6 +34,7 @@ namespace MalwareMultiScan.Api.Services _logger = logger; } + /// public Task StartAsync(CancellationToken cancellationToken) { _bus.Receive(_configuration.GetValue("ResultsSubscriptionId"), async message => @@ -31,21 +42,24 @@ namespace MalwareMultiScan.Api.Services _logger.LogInformation( $"Received a result from {message.Backend} for {message.Id} " + $"with threats {string.Join(",", message.Threats)}"); - + await _scanResultService.UpdateScanResultForBackend( - message.Id, message.Backend, true, true, message.Threats); + message.Id, message.Backend, true, + message.Succeeded, message.Threats ?? new string[] { }); }); - + _logger.LogInformation( "Started hosted service for receiving scan results"); return Task.CompletedTask; } + + /// public Task StopAsync(CancellationToken cancellationToken) { _bus.Dispose(); - + _logger.LogInformation( "Stopped hosted service for receiving scan results"); diff --git a/MalwareMultiScan.Api/Services/ScanBackendService.cs b/MalwareMultiScan.Api/Services/ScanBackendService.cs index d8926b9..71ca347 100644 --- a/MalwareMultiScan.Api/Services/ScanBackendService.cs +++ b/MalwareMultiScan.Api/Services/ScanBackendService.cs @@ -12,11 +12,21 @@ using YamlDotNet.Serialization.NamingConventions; namespace MalwareMultiScan.Api.Services { + /// + /// Scan backends service. + /// public class ScanBackendService { private readonly IBus _bus; private readonly ILogger _logger; + /// + /// Create scan backend service. + /// + /// Configuration. + /// Service bus. + /// Logger. + /// Missing BackendsConfiguration YAML file. public ScanBackendService(IConfiguration configuration, IBus bus, ILogger logger) { _bus = bus; @@ -36,13 +46,22 @@ namespace MalwareMultiScan.Api.Services List = deserializer.Deserialize(configurationContent); } + /// + /// List of available scan backends. + /// public ScanBackend[] List { get; } + /// + /// Queue URL scan. + /// + /// Scan result instance. + /// Scan backend. + /// File download URL. public async Task QueueUrlScan(ScanResult result, ScanBackend backend, string fileUrl) { _logger.LogInformation( $"Queueing scan for {result.Id} on {backend.Id} at {fileUrl}"); - + await _bus.SendAsync(backend.Id, new ScanRequestMessage { Id = result.Id, diff --git a/MalwareMultiScan.Api/Services/ScanResultService.cs b/MalwareMultiScan.Api/Services/ScanResultService.cs index 93b1926..231c88e 100644 --- a/MalwareMultiScan.Api/Services/ScanResultService.cs +++ b/MalwareMultiScan.Api/Services/ScanResultService.cs @@ -8,29 +8,41 @@ using MongoDB.Driver.GridFS; namespace MalwareMultiScan.Api.Services { + /// + /// Scan results service. + /// public class ScanResultService { private const string CollectionName = "ScanResults"; + private readonly GridFSBucket _bucket; - private readonly IMongoCollection _collection; - private readonly ScanBackendService _scanBackendService; + /// + /// Create scan result service. + /// + /// Mongo database. + /// Scan backend service. public ScanResultService(IMongoDatabase db, ScanBackendService scanBackendService) { _scanBackendService = scanBackendService; - _collection = db.GetCollection(CollectionName); _bucket = new GridFSBucket(db); + _collection = db.GetCollection(CollectionName); } + /// + /// Create scan result. + /// + /// Scan result. public async Task CreateScanResult() { var scanResult = new ScanResult { - Results = _scanBackendService.List.ToDictionary( - k => k.Id, v => new ScanResultEntry()) + Results = _scanBackendService.List + .Where(b => b.Enabled) + .ToDictionary(k => k.Id, v => new ScanResultEntry()) }; await _collection.InsertOneAsync(scanResult); @@ -38,6 +50,11 @@ namespace MalwareMultiScan.Api.Services return scanResult; } + /// + /// Get scan result. + /// + /// Scan result id. + /// Scan result. public async Task GetScanResult(string id) { var result = await _collection.FindAsync( @@ -46,27 +63,44 @@ namespace MalwareMultiScan.Api.Services return await result.FirstOrDefaultAsync(); } + /// + /// Update scan status for the backend. + /// + /// Result id. + /// Backend id. + /// If the scan has been completed. + /// If the scan has been succeeded. + /// List of found threats. public async Task UpdateScanResultForBackend(string resultId, string backendId, bool completed = false, bool succeeded = false, string[] threats = null) { - var filterScanResult = Builders.Filter.Where(r => r.Id == resultId); - - var updateScanResult = Builders.Update.Set(r => r.Results[backendId], new ScanResultEntry - { - Completed = completed, - Succeeded = succeeded, - Threats = threats - }); - - await _collection.UpdateOneAsync(filterScanResult, updateScanResult); + await _collection.UpdateOneAsync( + Builders.Filter.Where(r => r.Id == resultId), + Builders.Update.Set(r => r.Results[backendId], new ScanResultEntry + { + Completed = completed, + Succeeded = succeeded, + Threats = threats ?? new string[] { } + })); } + /// + /// Queue URL scan. + /// + /// Scan result instance. + /// File URL. public async Task QueueUrlScan(ScanResult result, string fileUrl) { - foreach (var backend in _scanBackendService.List) + foreach (var backend in _scanBackendService.List.Where(b => b.Enabled)) await _scanBackendService.QueueUrlScan(result, backend, fileUrl); } + /// + /// Store file. + /// + /// File name. + /// File stream. + /// Stored file id. public async Task StoreFile(string fileName, Stream fileStream) { var objectId = await _bucket.UploadFromStreamAsync( @@ -75,6 +109,11 @@ namespace MalwareMultiScan.Api.Services return objectId.ToString(); } + /// + /// Obtain stored file stream. + /// + /// File id. + /// File seekable stream. public async Task ObtainFile(string id) { if (!ObjectId.TryParse(id, out var objectId)) diff --git a/MalwareMultiScan.Api/Startup.cs b/MalwareMultiScan.Api/Startup.cs index 6fbc9ec..5039640 100644 --- a/MalwareMultiScan.Api/Startup.cs +++ b/MalwareMultiScan.Api/Startup.cs @@ -1,12 +1,8 @@ -using EasyNetQ; +using MalwareMultiScan.Api.Extensions; using MalwareMultiScan.Api.Services; using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.HttpOverrides; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Microsoft.OpenApi.Models; -using MongoDB.Driver; namespace MalwareMultiScan.Api { @@ -21,62 +17,24 @@ namespace MalwareMultiScan.Api public void ConfigureServices(IServiceCollection services) { - services.AddSingleton(x => - RabbitHutch.CreateBus(_configuration.GetConnectionString("RabbitMQ"))); + services.AddDockerForwardedHeadersOptions(); + + services.AddMongoDb(_configuration); + services.AddRabbitMq(_configuration); services.AddSingleton(); services.AddSingleton(); - services.AddSingleton( - serviceProvider => - { - var db = new MongoClient(_configuration.GetConnectionString("Mongo")); - - return db.GetDatabase( - _configuration.GetValue("DatabaseName")); - }); - services.AddControllers(); - services.AddHttpClient(); - - services.AddSwaggerGen(options => - { - options.SwaggerDoc("MalwareMultiScan", - new OpenApiInfo - { - Title = "MalwareMultiScan", - Version = "1.0.0" - }); - }); services.AddHostedService(); } - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + public void Configure(IApplicationBuilder app) { app.UseRouting(); - - var forwardingOptions = new ForwardedHeadersOptions - { - ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto - }; - - forwardingOptions.KnownNetworks.Clear(); - forwardingOptions.KnownProxies.Clear(); - - app.UseForwardedHeaders(forwardingOptions); - + app.UseForwardedHeaders(); app.UseEndpoints(endpoints => endpoints.MapControllers()); - - app.UseSwagger(); - - app.UseSwaggerUI(options => - { - options.DocumentTitle = "MalwareMultiScan"; - - options.SwaggerEndpoint( - $"/swagger/{options.DocumentTitle}/swagger.json", options.DocumentTitle); - }); } } } \ No newline at end of file diff --git a/MalwareMultiScan.Api/appsettings.Development.json b/MalwareMultiScan.Api/appsettings.Development.json deleted file mode 100644 index 8983e0f..0000000 --- a/MalwareMultiScan.Api/appsettings.Development.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft": "Warning", - "Microsoft.Hosting.Lifetime": "Information" - } - } -} diff --git a/MalwareMultiScan.Api/appsettings.json b/MalwareMultiScan.Api/appsettings.json index 1f83738..c2e1ca1 100644 --- a/MalwareMultiScan.Api/appsettings.json +++ b/MalwareMultiScan.Api/appsettings.json @@ -14,8 +14,7 @@ }, "DatabaseName": "MalwareMultiScan", - "ResultsSubscriptionId": "mms.results", - + "MaxFileSize": 1048576, "BackendsConfiguration": "backends.yaml" } diff --git a/MalwareMultiScan.Api/backends.yaml b/MalwareMultiScan.Api/backends.yaml index 2c35e07..586e21a 100644 --- a/MalwareMultiScan.Api/backends.yaml +++ b/MalwareMultiScan.Api/backends.yaml @@ -1,2 +1,2 @@ - id: dummy - name: Dummy Backend \ No newline at end of file + enabled: true \ No newline at end of file diff --git a/MalwareMultiScan.Backends/Backends/Abstracts/AbstractLocalProcessScanBackend.cs b/MalwareMultiScan.Backends/Backends/Abstracts/AbstractLocalProcessScanBackend.cs index b00dc5b..802750c 100644 --- a/MalwareMultiScan.Backends/Backends/Abstracts/AbstractLocalProcessScanBackend.cs +++ b/MalwareMultiScan.Backends/Backends/Abstracts/AbstractLocalProcessScanBackend.cs @@ -20,7 +20,7 @@ namespace MalwareMultiScan.Backends.Backends.Abstracts protected abstract Regex MatchRegex { get; } protected abstract string BackendPath { get; } - protected virtual bool ParseStdErr { get; } + protected virtual bool ParseStdErr { get; } = false; protected virtual bool ThrowOnNonZeroExitCode { get; } = true; protected abstract string GetBackendArguments(string path); diff --git a/MalwareMultiScan.Backends/Backends/Abstracts/AbstractScanBackend.cs b/MalwareMultiScan.Backends/Backends/Abstracts/AbstractScanBackend.cs index 03aa90a..6229b1f 100644 --- a/MalwareMultiScan.Backends/Backends/Abstracts/AbstractScanBackend.cs +++ b/MalwareMultiScan.Backends/Backends/Abstracts/AbstractScanBackend.cs @@ -4,7 +4,6 @@ using System.Net.Http; using System.Threading; using System.Threading.Tasks; using MalwareMultiScan.Backends.Interfaces; -using Microsoft.AspNetCore.Http; namespace MalwareMultiScan.Backends.Backends.Abstracts { @@ -23,13 +22,6 @@ namespace MalwareMultiScan.Backends.Backends.Abstracts return await ScanAsync(uriStream, cancellationToken); } - public async Task ScanAsync(IFormFile file, CancellationToken cancellationToken) - { - await using var fileStream = file.OpenReadStream(); - - return await ScanAsync(fileStream, cancellationToken); - } - public async Task ScanAsync(Stream stream, CancellationToken cancellationToken) { var tempFile = Path.GetTempFileName(); diff --git a/MalwareMultiScan.Backends/Backends/Implementations/DummyScanBackend.cs b/MalwareMultiScan.Backends/Backends/Implementations/DummyScanBackend.cs index fb70597..b835515 100644 --- a/MalwareMultiScan.Backends/Backends/Implementations/DummyScanBackend.cs +++ b/MalwareMultiScan.Backends/Backends/Implementations/DummyScanBackend.cs @@ -3,7 +3,6 @@ using System.IO; using System.Threading; using System.Threading.Tasks; using MalwareMultiScan.Backends.Interfaces; -using Microsoft.AspNetCore.Http; namespace MalwareMultiScan.Backends.Backends.Implementations { @@ -21,11 +20,6 @@ namespace MalwareMultiScan.Backends.Backends.Implementations return Scan(); } - public Task ScanAsync(IFormFile file, CancellationToken cancellationToken) - { - return Scan(); - } - public Task ScanAsync(Stream stream, CancellationToken cancellationToken) { return Scan(); diff --git a/MalwareMultiScan.Backends/Dockerfiles/Clamav.Dockerfile b/MalwareMultiScan.Backends/Dockerfiles/Clamav.Dockerfile index 310618e..dd34136 100644 --- a/MalwareMultiScan.Backends/Dockerfiles/Clamav.Dockerfile +++ b/MalwareMultiScan.Backends/Dockerfiles/Clamav.Dockerfile @@ -1,4 +1,4 @@ -FROM mindcollapse/malware-multi-scan-worker:latest +FROM mindcollapse/malware-multi-scan-scanner:latest ENV DEBIAN_FRONTEND noninteractive diff --git a/MalwareMultiScan.Backends/Dockerfiles/Comodo.Dockerfile b/MalwareMultiScan.Backends/Dockerfiles/Comodo.Dockerfile index 7ebead2..8e10c16 100644 --- a/MalwareMultiScan.Backends/Dockerfiles/Comodo.Dockerfile +++ b/MalwareMultiScan.Backends/Dockerfiles/Comodo.Dockerfile @@ -1,4 +1,4 @@ -FROM mindcollapse/malware-multi-scan-worker:latest +FROM mindcollapse/malware-multi-scan-scanner:latest RUN apt-get update && apt-get install wget -y diff --git a/MalwareMultiScan.Backends/Dockerfiles/DrWeb.Dockerfile b/MalwareMultiScan.Backends/Dockerfiles/DrWeb.Dockerfile index 168156f..c6073db 100644 --- a/MalwareMultiScan.Backends/Dockerfiles/DrWeb.Dockerfile +++ b/MalwareMultiScan.Backends/Dockerfiles/DrWeb.Dockerfile @@ -1,4 +1,4 @@ -FROM mindcollapse/malware-multi-scan-worker:latest +FROM mindcollapse/malware-multi-scan-scanner:latest ARG DRWEB_KEY ENV DRWEB_KEY=$DRWEB_KEY diff --git a/MalwareMultiScan.Backends/Dockerfiles/KES.Dockerfile b/MalwareMultiScan.Backends/Dockerfiles/KES.Dockerfile index 5a7fbd6..80cff17 100644 --- a/MalwareMultiScan.Backends/Dockerfiles/KES.Dockerfile +++ b/MalwareMultiScan.Backends/Dockerfiles/KES.Dockerfile @@ -1,4 +1,4 @@ -FROM mindcollapse/malware-multi-scan-worker:latest +FROM mindcollapse/malware-multi-scan-scanner:latest ARG KES_KEY ENV KES_KEY=$KES_KEY diff --git a/MalwareMultiScan.Backends/Dockerfiles/McAfee.Dockerfile b/MalwareMultiScan.Backends/Dockerfiles/McAfee.Dockerfile index b8dd8d4..8dadd87 100644 --- a/MalwareMultiScan.Backends/Dockerfiles/McAfee.Dockerfile +++ b/MalwareMultiScan.Backends/Dockerfiles/McAfee.Dockerfile @@ -1,4 +1,4 @@ -FROM mindcollapse/malware-multi-scan-worker:latest +FROM mindcollapse/malware-multi-scan-scanner:latest RUN apt-get update && apt-get install unzip wget -y diff --git a/MalwareMultiScan.Backends/Dockerfiles/Sophos.Dockerfile b/MalwareMultiScan.Backends/Dockerfiles/Sophos.Dockerfile index ce57e8b..814309d 100644 --- a/MalwareMultiScan.Backends/Dockerfiles/Sophos.Dockerfile +++ b/MalwareMultiScan.Backends/Dockerfiles/Sophos.Dockerfile @@ -1,4 +1,4 @@ -FROM mindcollapse/malware-multi-scan-worker:latest +FROM mindcollapse/malware-multi-scan-scanner:latest RUN apt-get update && apt-get install wget -y diff --git a/MalwareMultiScan.Backends/Dockerfiles/WindowsDefender.Dockerfile b/MalwareMultiScan.Backends/Dockerfiles/WindowsDefender.Dockerfile index 6444031..b97083f 100644 --- a/MalwareMultiScan.Backends/Dockerfiles/WindowsDefender.Dockerfile +++ b/MalwareMultiScan.Backends/Dockerfiles/WindowsDefender.Dockerfile @@ -11,7 +11,7 @@ WORKDIR /opt/loadlibrary/engine RUN curl -L "https://go.microsoft.com/fwlink/?LinkID=121721&arch=x86" --output mpan-fe.exe RUN cabextract mpan-fe.exe && rm mpan-fe.exe -FROM mindcollapse/malware-multi-scan-worker:latest +FROM mindcollapse/malware-multi-scan-scanner:latest RUN apt-get update && apt-get install -y libc6-i386 diff --git a/MalwareMultiScan.Backends/Interfaces/IScanBackend.cs b/MalwareMultiScan.Backends/Interfaces/IScanBackend.cs index b234ce5..ea872f1 100644 --- a/MalwareMultiScan.Backends/Interfaces/IScanBackend.cs +++ b/MalwareMultiScan.Backends/Interfaces/IScanBackend.cs @@ -2,17 +2,14 @@ using System; using System.IO; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; namespace MalwareMultiScan.Backends.Interfaces { public interface IScanBackend { public string Id { get; } - public Task ScanAsync(string path, CancellationToken cancellationToken); public Task ScanAsync(Uri uri, CancellationToken cancellationToken); - public Task ScanAsync(IFormFile file, CancellationToken cancellationToken); public Task ScanAsync(Stream stream, CancellationToken cancellationToken); } } \ No newline at end of file diff --git a/MalwareMultiScan.Backends/MalwareMultiScan.Backends.csproj b/MalwareMultiScan.Backends/MalwareMultiScan.Backends.csproj index 0ce0c90..ae69f21 100644 --- a/MalwareMultiScan.Backends/MalwareMultiScan.Backends.csproj +++ b/MalwareMultiScan.Backends/MalwareMultiScan.Backends.csproj @@ -3,13 +3,10 @@ netcoreapp3.1 - - - - - + + diff --git a/MalwareMultiScan.Backends/Messages/ScanResultMessage.cs b/MalwareMultiScan.Backends/Messages/ScanResultMessage.cs index f6627d7..21807b7 100644 --- a/MalwareMultiScan.Backends/Messages/ScanResultMessage.cs +++ b/MalwareMultiScan.Backends/Messages/ScanResultMessage.cs @@ -4,6 +4,8 @@ namespace MalwareMultiScan.Backends.Messages { public string Id { get; set; } public string Backend { get; set; } + + public bool Succeeded { get; set; } public string[] Threats { get; set; } } } \ No newline at end of file diff --git a/MalwareMultiScan.Scanner/Dockerfile b/MalwareMultiScan.Scanner/Dockerfile index 1791d67..bab5501 100644 --- a/MalwareMultiScan.Scanner/Dockerfile +++ b/MalwareMultiScan.Scanner/Dockerfile @@ -2,11 +2,10 @@ FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS builder WORKDIR /src -COPY MalwareMultiScan.Worker /src/MalwareMultiScan.Worker -COPY MalwareMultiScan.Shared /src/MalwareMultiScan.Shared +COPY MalwareMultiScan.Worker /src/MalwareMultiScan.Scanner COPY MalwareMultiScan.Backends /src/MalwareMultiScan.Backends -RUN dotnet publish -c Release -r linux-x64 -o ./publish MalwareMultiScan.Worker/MalwareMultiScan.Worker.csproj +RUN dotnet publish -c Release -r linux-x64 -o ./publish MalwareMultiScan.Scanner/MalwareMultiScan.Scanner.csproj FROM mcr.microsoft.com/dotnet/core/aspnet:3.1 @@ -14,7 +13,4 @@ WORKDIR /worker COPY --from=builder /src/publish /worker -ENV ASPNETCORE_ENVIRONMENT=Production -ENV ASPNETCORE_URLS=http://+:9901 - -ENTRYPOINT ["/worker/MalwareMultiScan.Worker"] \ No newline at end of file +ENTRYPOINT ["/worker/MalwareMultiScan.Scanner"] \ No newline at end of file diff --git a/MalwareMultiScan.Scanner/MalwareMultiScan.Scanner.csproj b/MalwareMultiScan.Scanner/MalwareMultiScan.Scanner.csproj index 5930542..2d98265 100644 --- a/MalwareMultiScan.Scanner/MalwareMultiScan.Scanner.csproj +++ b/MalwareMultiScan.Scanner/MalwareMultiScan.Scanner.csproj @@ -11,10 +11,5 @@ - - - - - <_ContentIncludedByDefault Remove="Properties\launchSettings.json" /> diff --git a/MalwareMultiScan.Scanner/Services/ScanHostedService.cs b/MalwareMultiScan.Scanner/Services/ScanHostedService.cs index 5c52d0d..f9dc666 100644 --- a/MalwareMultiScan.Scanner/Services/ScanHostedService.cs +++ b/MalwareMultiScan.Scanner/Services/ScanHostedService.cs @@ -56,28 +56,35 @@ namespace MalwareMultiScan.Scanner.Services var cancellationTokenSource = new CancellationTokenSource( TimeSpan.FromSeconds(_configuration.GetValue("MaxScanningTime"))); + var result = new ScanResultMessage + { + Id = message.Id, + Backend = _backend.Id + }; + try { - var result = new ScanResultMessage - { - Id = message.Id, - Backend = _backend.Id, + result.Threats = await _backend.ScanAsync( + message.Uri, cancellationTokenSource.Token); - Threats = await _backend.ScanAsync( - message.Uri, cancellationTokenSource.Token) - }; + result.Succeeded = true; _logger.LogInformation( $"Backend {_backend.Id} completed a scan of {message.Id} " + $"with result '{string.Join(", ", result.Threats)}'"); - - await _bus.SendAsync(_configuration.GetValue("ResultsSubscriptionId"), result); } catch (Exception exception) { + result.Succeeded = false; + _logger.LogError( exception, "Scanning failed with exception"); } + finally + { + await _bus.SendAsync( + _configuration.GetValue("ResultsSubscriptionId"), result); + } } } } \ No newline at end of file