2020-10-20 17:08:40 +03:00

107 lines
3.7 KiB
C#

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),
_ => 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.Name
};
try
{
response.Success = true;
response.Threats = await scanMethod(cancellationToken);
response.DatabaseLastUpdate = _backend.DatabaseLastUpdate;
}
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);
}
}
}
}