mirror of
https://github.com/volodymyrsmirnov/MalwareMultiScan.git
synced 2025-08-24 05:22:22 +00:00
refactoring, documentation pending
This commit is contained in:
parent
29156b7f10
commit
14c9c26979
@ -1,16 +1,16 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace MalwareMultiScan.Shared.Attributes
|
||||
namespace MalwareMultiScan.Api.Attributes
|
||||
{
|
||||
public class UrlValidationAttribute : ValidationAttribute
|
||||
public class HttpUrlValidationAttribute : ValidationAttribute
|
||||
{
|
||||
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
|
||||
{
|
||||
var uri = (Uri) value;
|
||||
|
||||
if (uri == null || !uri.IsAbsoluteUri || uri.Scheme != "http" && uri.Scheme != "https")
|
||||
return new ValidationResult("Only http(s) absolute URLs are supported");
|
||||
return new ValidationResult("Only absolute http(s) URLs are supported");
|
||||
|
||||
return ValidationResult.Success;
|
||||
}
|
@ -1,9 +1,8 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using MalwareMultiScan.Api.Attributes;
|
||||
using MalwareMultiScan.Api.Data.Models;
|
||||
using MalwareMultiScan.Api.Services;
|
||||
using MalwareMultiScan.Shared.Attributes;
|
||||
using MalwareMultiScan.Shared.Data.Responses;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
@ -16,13 +15,13 @@ namespace MalwareMultiScan.Api.Controllers
|
||||
{
|
||||
private readonly ScanResultService _scanResultService;
|
||||
|
||||
public QueueController( ScanResultService scanResultService)
|
||||
public QueueController(ScanResultService scanResultService)
|
||||
{
|
||||
_scanResultService = scanResultService;
|
||||
}
|
||||
|
||||
[HttpPost("file")]
|
||||
[ProducesResponseType(typeof(ResultResponse), StatusCodes.Status201Created)]
|
||||
[ProducesResponseType(typeof(ScanResult), StatusCodes.Status201Created)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
public async Task<IActionResult> ScanFile([FromForm] IFormFile file)
|
||||
{
|
||||
@ -31,7 +30,9 @@ namespace MalwareMultiScan.Api.Controllers
|
||||
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));
|
||||
@ -41,9 +42,9 @@ namespace MalwareMultiScan.Api.Controllers
|
||||
}
|
||||
|
||||
[HttpPost("url")]
|
||||
[ProducesResponseType(typeof(ResultResponse), StatusCodes.Status201Created)]
|
||||
[ProducesResponseType(typeof(ScanResult), StatusCodes.Status201Created)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
public async Task<IActionResult> ScanUrl([FromForm] [UrlValidation] Uri url)
|
||||
public async Task<IActionResult> ScanUrl([FromForm] [HttpUrlValidation] Uri url)
|
||||
{
|
||||
var result = await _scanResultService.CreateScanResult();
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
using System.Threading.Tasks;
|
||||
using MalwareMultiScan.Api.Data.Models;
|
||||
using MalwareMultiScan.Api.Services;
|
||||
using MalwareMultiScan.Shared.Data.Responses;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
|
@ -1,9 +0,0 @@
|
||||
namespace MalwareMultiScan.Api.Data.Response
|
||||
{
|
||||
public class ScanBackendResponse
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public bool Online { get; set; }
|
||||
}
|
||||
}
|
@ -23,6 +23,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MalwareMultiScan.Backends\MalwareMultiScan.Backends.csproj" />
|
||||
<ProjectReference Include="..\MalwareMultiScan.Shared\MalwareMultiScan.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
@ -1,9 +1,10 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using EasyNetQ;
|
||||
using MalwareMultiScan.Shared.Data.Messages;
|
||||
using MalwareMultiScan.Backends.Messages;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace MalwareMultiScan.Api.Services
|
||||
{
|
||||
@ -12,22 +13,32 @@ namespace MalwareMultiScan.Api.Services
|
||||
private readonly IBus _bus;
|
||||
private readonly IConfiguration _configuration;
|
||||
private readonly ScanResultService _scanResultService;
|
||||
private readonly ILogger<ReceiverHostedService> _logger;
|
||||
|
||||
public ReceiverHostedService(IBus bus, IConfiguration configuration, ScanResultService scanResultService)
|
||||
public ReceiverHostedService(IBus bus, IConfiguration configuration, ScanResultService scanResultService,
|
||||
ILogger<ReceiverHostedService> logger)
|
||||
{
|
||||
_bus = bus;
|
||||
_configuration = configuration;
|
||||
_scanResultService = scanResultService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_bus.Receive<ScanResultMessage>(_configuration.GetValue<string>("ResultsSubscriptionId"), async message =>
|
||||
{
|
||||
_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);
|
||||
});
|
||||
|
||||
_logger.LogInformation(
|
||||
"Started hosted service for receiving scan results");
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
@ -35,6 +46,9 @@ namespace MalwareMultiScan.Api.Services
|
||||
{
|
||||
_bus.Dispose();
|
||||
|
||||
_logger.LogInformation(
|
||||
"Stopped hosted service for receiving scan results");
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
@ -4,8 +4,9 @@ using System.Threading.Tasks;
|
||||
using EasyNetQ;
|
||||
using MalwareMultiScan.Api.Data.Configuration;
|
||||
using MalwareMultiScan.Api.Data.Models;
|
||||
using MalwareMultiScan.Shared.Data.Messages;
|
||||
using MalwareMultiScan.Backends.Messages;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using YamlDotNet.Serialization;
|
||||
using YamlDotNet.Serialization.NamingConventions;
|
||||
|
||||
@ -14,10 +15,12 @@ namespace MalwareMultiScan.Api.Services
|
||||
public class ScanBackendService
|
||||
{
|
||||
private readonly IBus _bus;
|
||||
private readonly ILogger<ScanBackendService> _logger;
|
||||
|
||||
public ScanBackendService(IConfiguration configuration, IBus bus)
|
||||
public ScanBackendService(IConfiguration configuration, IBus bus, ILogger<ScanBackendService> logger)
|
||||
{
|
||||
_bus = bus;
|
||||
_logger = logger;
|
||||
|
||||
var configurationPath = configuration.GetValue<string>("BackendsConfiguration");
|
||||
|
||||
@ -37,6 +40,9 @@ namespace MalwareMultiScan.Api.Services
|
||||
|
||||
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,
|
||||
|
@ -1,13 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MalwareMultiScan.Api.Data.Configuration;
|
||||
using MalwareMultiScan.Api.Data.Models;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MongoDB.Bson;
|
||||
using MongoDB.Driver;
|
||||
using MongoDB.Driver.GridFS;
|
||||
@ -17,9 +11,9 @@ namespace MalwareMultiScan.Api.Services
|
||||
public class ScanResultService
|
||||
{
|
||||
private const string CollectionName = "ScanResults";
|
||||
private readonly GridFSBucket _bucket;
|
||||
|
||||
private readonly IMongoCollection<ScanResult> _collection;
|
||||
private readonly GridFSBucket _bucket;
|
||||
|
||||
private readonly ScanBackendService _scanBackendService;
|
||||
|
||||
|
@ -18,15 +18,12 @@ namespace MalwareMultiScan.Backends.Backends.Abstracts
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
protected virtual Regex MatchRegex { get; }
|
||||
protected virtual string BackendPath { get; }
|
||||
protected abstract Regex MatchRegex { get; }
|
||||
protected abstract string BackendPath { get; }
|
||||
protected virtual bool ParseStdErr { get; }
|
||||
protected virtual bool ThrowOnNonZeroExitCode { get; } = true;
|
||||
|
||||
protected virtual string GetBackendArguments(string path)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
protected abstract string GetBackendArguments(string path);
|
||||
|
||||
public override async Task<string[]> ScanAsync(string path, CancellationToken cancellationToken)
|
||||
{
|
||||
|
@ -3,23 +3,21 @@ using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MalwareMultiScan.Shared.Interfaces;
|
||||
using MalwareMultiScan.Backends.Interfaces;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace MalwareMultiScan.Backends.Backends.Abstracts
|
||||
{
|
||||
public abstract class AbstractScanBackend : IScanBackend
|
||||
{
|
||||
public virtual string Id => throw new NotImplementedException();
|
||||
public abstract string Id { get; }
|
||||
|
||||
public virtual Task<string[]> ScanAsync(string path, CancellationToken cancellationToken)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public abstract Task<string[]> ScanAsync(string path, CancellationToken cancellationToken);
|
||||
|
||||
public async Task<string[]> ScanAsync(Uri uri, CancellationToken cancellationToken)
|
||||
{
|
||||
using var httpClient = new HttpClient();
|
||||
|
||||
await using var uriStream = await httpClient.GetStreamAsync(uri);
|
||||
|
||||
return await ScanAsync(uriStream, cancellationToken);
|
||||
|
@ -1,5 +1,3 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using MalwareMultiScan.Backends.Backends.Abstracts;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
@ -2,7 +2,7 @@ using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MalwareMultiScan.Shared.Interfaces;
|
||||
using MalwareMultiScan.Backends.Interfaces;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace MalwareMultiScan.Backends.Backends.Implementations
|
||||
|
@ -1,4 +1,4 @@
|
||||
namespace MalwareMultiScan.Shared.Data.Enums
|
||||
namespace MalwareMultiScan.Backends.Enums
|
||||
{
|
||||
public enum BackendType
|
||||
{
|
@ -1,11 +1,11 @@
|
||||
using System;
|
||||
using MalwareMultiScan.Backends.Backends.Implementations;
|
||||
using MalwareMultiScan.Shared.Data.Enums;
|
||||
using MalwareMultiScan.Shared.Interfaces;
|
||||
using MalwareMultiScan.Backends.Enums;
|
||||
using MalwareMultiScan.Backends.Interfaces;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace MalwareMultiScan.Scanner.Extensions
|
||||
namespace MalwareMultiScan.Backends.Extensions
|
||||
{
|
||||
public static class ServiceCollectionExtensions
|
||||
{
|
||||
@ -13,7 +13,7 @@ namespace MalwareMultiScan.Scanner.Extensions
|
||||
{
|
||||
using var provider = services.BuildServiceProvider();
|
||||
|
||||
var logger = provider.GetService<ILogger>();
|
||||
var logger = provider.GetService<ILogger<IScanBackend>>();
|
||||
|
||||
services.AddSingleton<IScanBackend>(type switch
|
||||
{
|
@ -4,7 +4,7 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace MalwareMultiScan.Shared.Interfaces
|
||||
namespace MalwareMultiScan.Backends.Interfaces
|
||||
{
|
||||
public interface IScanBackend
|
||||
{
|
@ -8,4 +8,8 @@
|
||||
<ProjectReference Include="..\MalwareMultiScan.Shared\MalwareMultiScan.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.9" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace MalwareMultiScan.Shared.Data.Messages
|
||||
namespace MalwareMultiScan.Backends.Messages
|
||||
{
|
||||
public class ScanRequestMessage
|
||||
{
|
@ -1,4 +1,4 @@
|
||||
namespace MalwareMultiScan.Shared.Data.Messages
|
||||
namespace MalwareMultiScan.Backends.Messages
|
||||
{
|
||||
public class ScanResultMessage
|
||||
{
|
@ -13,4 +13,8 @@
|
||||
<ProjectReference Include="..\MalwareMultiScan.Backends\MalwareMultiScan.Backends.csproj" />
|
||||
<ProjectReference Include="..\MalwareMultiScan.Shared\MalwareMultiScan.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<_ContentIncludedByDefault Remove="Properties\launchSettings.json" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@ -1,6 +1,7 @@
|
||||
using System.Threading.Tasks;
|
||||
using MalwareMultiScan.Scanner.Extensions;
|
||||
using MalwareMultiScan.Shared.Data.Enums;
|
||||
using MalwareMultiScan.Backends.Enums;
|
||||
using MalwareMultiScan.Backends.Extensions;
|
||||
using MalwareMultiScan.Scanner.Services;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
@ -14,7 +15,7 @@ namespace MalwareMultiScan.Scanner
|
||||
await Host.CreateDefaultBuilder(args)
|
||||
.ConfigureAppConfiguration(configure =>
|
||||
{
|
||||
configure.AddJsonFile("settings.json");
|
||||
configure.AddJsonFile("appsettings.json");
|
||||
configure.AddEnvironmentVariables();
|
||||
})
|
||||
.ConfigureServices((context, services) =>
|
||||
|
@ -1,10 +0,0 @@
|
||||
{
|
||||
"profiles": {
|
||||
"MalwareMultiScan.Scanner": {
|
||||
"commandName": "Project",
|
||||
"environmentVariables": {
|
||||
"DOTNET_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -2,27 +2,27 @@ using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using EasyNetQ;
|
||||
using MalwareMultiScan.Shared.Data.Messages;
|
||||
using MalwareMultiScan.Shared.Interfaces;
|
||||
using MalwareMultiScan.Backends.Interfaces;
|
||||
using MalwareMultiScan.Backends.Messages;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace MalwareMultiScan.Scanner
|
||||
namespace MalwareMultiScan.Scanner.Services
|
||||
{
|
||||
public class ScanHostedService : IHostedService
|
||||
internal class ScanHostedService : IHostedService
|
||||
{
|
||||
private readonly IScanBackend _backend;
|
||||
private readonly IConfiguration _configuration;
|
||||
private readonly ILogger<ScanHostedService> _logger;
|
||||
private readonly IScanBackend _scanBackend;
|
||||
|
||||
private IBus _bus;
|
||||
|
||||
public ScanHostedService(ILogger<ScanHostedService> logger, IConfiguration configuration, IScanBackend scanBackend)
|
||||
public ScanHostedService(ILogger<ScanHostedService> logger, IConfiguration configuration, IScanBackend backend)
|
||||
{
|
||||
_logger = logger;
|
||||
_configuration = configuration;
|
||||
_scanBackend = scanBackend;
|
||||
_backend = backend;
|
||||
}
|
||||
|
||||
public Task StartAsync(CancellationToken cancellationToken)
|
||||
@ -30,38 +30,48 @@ namespace MalwareMultiScan.Scanner
|
||||
_bus = RabbitHutch.CreateBus(
|
||||
_configuration.GetConnectionString("RabbitMQ"));
|
||||
|
||||
_bus.Receive<ScanRequestMessage>(
|
||||
_scanBackend.Id, Scan);
|
||||
_bus.Receive<ScanRequestMessage>(_backend.Id, Scan);
|
||||
|
||||
_logger.LogInformation(
|
||||
$"Started scan hosting service for the backend {_backend.Id}");
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_bus.Dispose();
|
||||
|
||||
_logger.LogInformation(
|
||||
$"Stopped scan hosting service for the backend {_backend.Id}");
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private async Task Scan(ScanRequestMessage message)
|
||||
{
|
||||
_logger.LogInformation(
|
||||
$"Starting scan of {message.Uri} via backend {_scanBackend.Id}");
|
||||
$"Starting scan of {message.Uri} via backend {_backend.Id} from {message.Id}");
|
||||
|
||||
var cancellationTokenSource = new CancellationTokenSource(
|
||||
TimeSpan.FromSeconds(_configuration.GetValue<int>("MaxScanningTime")));
|
||||
|
||||
try
|
||||
{
|
||||
await _bus.SendAsync(_configuration.GetValue<string>("ResultsSubscriptionId"), new ScanResultMessage
|
||||
var result = new ScanResultMessage
|
||||
{
|
||||
Id = message.Id,
|
||||
Backend = _scanBackend.Id,
|
||||
Backend = _backend.Id,
|
||||
|
||||
Threats = await _scanBackend.ScanAsync(
|
||||
Threats = await _backend.ScanAsync(
|
||||
message.Uri, cancellationTokenSource.Token)
|
||||
});
|
||||
};
|
||||
|
||||
_logger.LogInformation(
|
||||
$"Backend {_backend.Id} completed a scan of {message.Id} " +
|
||||
$"with result '{string.Join(", ", result.Threats)}'");
|
||||
|
||||
await _bus.SendAsync(_configuration.GetValue<string>("ResultsSubscriptionId"), result);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
@ -9,9 +9,7 @@
|
||||
|
||||
"BackendType": "Dummy",
|
||||
|
||||
"MaxWorkers": 5,
|
||||
"MaxScanningTime": 60,
|
||||
|
||||
"ResultsSubscriptionId": "mms.results",
|
||||
|
||||
"ConnectionStrings": {
|
@ -1,13 +0,0 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using MalwareMultiScan.Shared.Attributes;
|
||||
|
||||
namespace MalwareMultiScan.Shared.Data.Requests
|
||||
{
|
||||
public abstract class BasicRequest
|
||||
{
|
||||
[Required]
|
||||
[UrlValidation]
|
||||
public Uri CallbackUrl { get; set; }
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace MalwareMultiScan.Shared.Data.Requests
|
||||
{
|
||||
public class FileRequest : BasicRequest
|
||||
{
|
||||
[Required]
|
||||
public IFormFile InputFile { get; set; }
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using MalwareMultiScan.Shared.Attributes;
|
||||
|
||||
namespace MalwareMultiScan.Shared.Data.Requests
|
||||
{
|
||||
public class UrlRequest : BasicRequest
|
||||
{
|
||||
[Required]
|
||||
[UrlValidation]
|
||||
public Uri InputUrl { get; set; }
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
|
||||
namespace MalwareMultiScan.Shared.Data.Responses
|
||||
{
|
||||
public class ResultResponse
|
||||
{
|
||||
[Required]
|
||||
public string Backend { get; set; }
|
||||
|
||||
[Required]
|
||||
public bool Success { get; set; }
|
||||
|
||||
public string[] Threats { get; set; }
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Http.Features" Version="3.1.9" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="3.1.9" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -1,55 +0,0 @@
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Hangfire;
|
||||
using MalwareMultiScan.Shared.Data.Requests;
|
||||
using MalwareMultiScan.Worker.Jobs;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace MalwareMultiScan.Worker.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Produces("application/json")]
|
||||
public class ScanController : ControllerBase
|
||||
{
|
||||
|
||||
[HttpGet]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[Route("/ping")]
|
||||
public IActionResult Ping()
|
||||
{
|
||||
return Ok("pong");
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ProducesResponseType(StatusCodes.Status202Accepted)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[Route("/scan/file")]
|
||||
public async Task<IActionResult> ScanFile([FromForm] FileRequest request)
|
||||
{
|
||||
var temporaryFile = Path.GetTempFileName();
|
||||
|
||||
await using (var temporaryFileSteam = System.IO.File.OpenWrite(temporaryFile))
|
||||
{
|
||||
await request.InputFile.CopyToAsync(temporaryFileSteam);
|
||||
}
|
||||
|
||||
BackgroundJob.Enqueue<ScanJob>(
|
||||
x => x.ScanFile(temporaryFile, request.CallbackUrl));
|
||||
|
||||
return Accepted(request.CallbackUrl);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ProducesResponseType(StatusCodes.Status202Accepted)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[Route("/scan/url")]
|
||||
public IActionResult ScanUrl([FromForm] UrlRequest request)
|
||||
{
|
||||
BackgroundJob.Enqueue<ScanJob>(
|
||||
x => x.ScanUrl(request.InputUrl, request.CallbackUrl));
|
||||
|
||||
return Accepted(request.CallbackUrl);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,111 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Hangfire;
|
||||
using MalwareMultiScan.Backends.Backends.Implementations;
|
||||
using MalwareMultiScan.Shared.Data.Enums;
|
||||
using MalwareMultiScan.Shared.Data.Responses;
|
||||
using MalwareMultiScan.Shared.Interfaces;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace MalwareMultiScan.Worker.Jobs
|
||||
{
|
||||
public class ScanJob
|
||||
{
|
||||
private readonly IScanBackend _backend;
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
private readonly ILogger<ScanJob> _logger;
|
||||
private readonly int _scanTimeout;
|
||||
|
||||
public ScanJob(IConfiguration configuration, ILogger<ScanJob> logger,
|
||||
IHttpClientFactory httpClientFactory)
|
||||
{
|
||||
_logger = logger;
|
||||
_httpClientFactory = httpClientFactory;
|
||||
_scanTimeout = configuration.GetValue<int>("ScanTimeout");
|
||||
|
||||
_backend = configuration.GetValue<BackendType>("BackendType") switch
|
||||
{
|
||||
BackendType.Defender => new WindowsDefenderScanBackend(logger),
|
||||
BackendType.Clamav => new ClamavScanBackend(logger),
|
||||
BackendType.DrWeb => new DrWebScanBackend(logger),
|
||||
BackendType.Kes => new KesScanBackend(logger),
|
||||
BackendType.Comodo => new ComodoScanBackend(logger),
|
||||
BackendType.Sophos => new SophosScanBackend(logger),
|
||||
BackendType.McAfee => new McAfeeScanBackend(logger),
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
}
|
||||
|
||||
private async Task PostResult(ResultResponse response, Uri callbackUrl, CancellationToken cancellationToken)
|
||||
{
|
||||
var serializedResponse = JsonSerializer.Serialize(
|
||||
response, typeof(ResultResponse), new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true
|
||||
});
|
||||
|
||||
_logger.LogInformation(
|
||||
$"Sending following payload to {callbackUrl}: {serializedResponse}");
|
||||
|
||||
using var httpClient = _httpClientFactory.CreateClient();
|
||||
|
||||
var callbackResponse = await httpClient.PostAsync(callbackUrl,
|
||||
new StringContent(serializedResponse, Encoding.UTF8, "application/json"), cancellationToken);
|
||||
|
||||
_logger.LogInformation($"Callback URL {callbackUrl} returned a status {callbackResponse.StatusCode}");
|
||||
}
|
||||
|
||||
private async Task Scan(Func<CancellationToken, Task<string[]>> scanMethod, Uri callbackUrl)
|
||||
{
|
||||
var cancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
cancellationTokenSource.CancelAfter(_scanTimeout * 1000);
|
||||
|
||||
var cancellationToken = cancellationTokenSource.Token;
|
||||
|
||||
var response = new ResultResponse
|
||||
{
|
||||
Backend = _backend.Id
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
response.Success = true;
|
||||
response.Threats = await scanMethod(cancellationToken);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
response.Success = false;
|
||||
|
||||
_logger.LogError(exception, "Scanning failed with exception");
|
||||
}
|
||||
|
||||
await PostResult(response, callbackUrl, cancellationToken);
|
||||
}
|
||||
|
||||
[AutomaticRetry(Attempts = 0, OnAttemptsExceeded = AttemptsExceededAction.Delete)]
|
||||
public async Task ScanUrl(Uri url, Uri callbackUrl)
|
||||
{
|
||||
await Scan(async t => await _backend.ScanAsync(url, t), callbackUrl);
|
||||
}
|
||||
|
||||
[AutomaticRetry(Attempts = 0, OnAttemptsExceeded = AttemptsExceededAction.Delete)]
|
||||
public async Task ScanFile(string file, Uri callbackUrl)
|
||||
{
|
||||
try
|
||||
{
|
||||
await Scan(async t => await _backend.ScanAsync(file, t), callbackUrl);
|
||||
}
|
||||
finally
|
||||
{
|
||||
File.Delete(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MalwareMultiScan.Backends\MalwareMultiScan.Backends.csproj" />
|
||||
<ProjectReference Include="..\MalwareMultiScan.Shared\MalwareMultiScan.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Hangfire.AspNetCore" Version="1.7.16" />
|
||||
<PackageReference Include="Hangfire.MemoryStorage" Version="1.7.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<_ContentIncludedByDefault Remove="Properties\launchSettings.json" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -1,19 +0,0 @@
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
namespace MalwareMultiScan.Worker
|
||||
{
|
||||
public static class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
CreateHostBuilder(args).Build().Run();
|
||||
}
|
||||
|
||||
private static IHostBuilder CreateHostBuilder(string[] args)
|
||||
{
|
||||
return Host.CreateDefaultBuilder(args)
|
||||
.ConfigureWebHostDefaults(builder => { builder.UseStartup<Startup>(); });
|
||||
}
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
using Hangfire;
|
||||
using Hangfire.MemoryStorage;
|
||||
using MalwareMultiScan.Worker.Jobs;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace MalwareMultiScan.Worker
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddLogging();
|
||||
services.AddControllers();
|
||||
services.AddHttpClient();
|
||||
|
||||
services.AddSingleton<ScanJob>();
|
||||
|
||||
services.AddHangfire(
|
||||
configuration => configuration.UseMemoryStorage());
|
||||
|
||||
services.AddHangfireServer();
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||
{
|
||||
app.UseRouting();
|
||||
|
||||
app.UseEndpoints(
|
||||
endpoints => endpoints.MapControllers());
|
||||
|
||||
app.UseHangfireServer();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Warning",
|
||||
"MalwareMultiScan": "Debug"
|
||||
}
|
||||
},
|
||||
|
||||
"AllowedHosts": "*",
|
||||
|
||||
"BackendType": "",
|
||||
"ScanTimeout": 300
|
||||
}
|
@ -1,9 +1,5 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MalwareMultiScan.Worker", "MalwareMultiScan.Worker\MalwareMultiScan.Worker.csproj", "{5D515E0A-B2C6-4C1D-88F6-C296F73409FA}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MalwareMultiScan.Shared", "MalwareMultiScan.Shared\MalwareMultiScan.Shared.csproj", "{9E0A0B50-741F-4A49-97A2-0B337374347F}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MalwareMultiScan.Backends", "MalwareMultiScan.Backends\MalwareMultiScan.Backends.csproj", "{382B49AC-0FFA-44FC-875D-9D4692DDC05D}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MalwareMultiScan.Api", "MalwareMultiScan.Api\MalwareMultiScan.Api.csproj", "{7B63B897-D390-4617-821F-F96799CBA2F4}"
|
||||
@ -16,14 +12,6 @@ Global
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{5D515E0A-B2C6-4C1D-88F6-C296F73409FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5D515E0A-B2C6-4C1D-88F6-C296F73409FA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5D515E0A-B2C6-4C1D-88F6-C296F73409FA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5D515E0A-B2C6-4C1D-88F6-C296F73409FA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{9E0A0B50-741F-4A49-97A2-0B337374347F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9E0A0B50-741F-4A49-97A2-0B337374347F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9E0A0B50-741F-4A49-97A2-0B337374347F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9E0A0B50-741F-4A49-97A2-0B337374347F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{382B49AC-0FFA-44FC-875D-9D4692DDC05D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{382B49AC-0FFA-44FC-875D-9D4692DDC05D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{382B49AC-0FFA-44FC-875D-9D4692DDC05D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
|
Loading…
x
Reference in New Issue
Block a user