using System; using System.IO; using System.Net.Http; using System.Threading; using System.Threading.Tasks; using MalwareMultiScan.Api.Data.Configuration; using MalwareMultiScan.Shared.Data.Requests; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using YamlDotNet.Serialization; using YamlDotNet.Serialization.NamingConventions; namespace MalwareMultiScan.Api.Services { public class ScanBackendService { private readonly IHttpClientFactory _httpClientFactory; private readonly ILogger _logger; public ScanBackendService(IConfiguration configuration, IHttpClientFactory httpClientFactory, ILogger logger) { _httpClientFactory = httpClientFactory; _logger = logger; var configurationPath = configuration.GetValue("BackendsConfiguration"); if (!File.Exists(configurationPath)) throw new FileNotFoundException("Missing BackendsConfiguration YAML file", configurationPath); var configurationContent = File.ReadAllText(configurationPath); var deserializer = new DeserializerBuilder() .WithNamingConvention(CamelCaseNamingConvention.Instance) .Build(); List = deserializer.Deserialize(configurationContent); } public ScanBackend[] List { get; } public async Task Ping(ScanBackend backend) { var cancellationTokenSource = new CancellationTokenSource( TimeSpan.FromSeconds(1)); try { using var httpClient = _httpClientFactory.CreateClient(); var pingResponse = await httpClient.GetAsync( new Uri(new Uri(backend.Endpoint), "/ping"), cancellationTokenSource.Token); pingResponse.EnsureSuccessStatusCode(); } catch (Exception exception) { _logger.LogError( exception, $"Failed to ping {backend.Id}"); return false; } return true; } private async Task QueueScan(ScanBackend backend, string uri, HttpContent content) { var cancellationTokenSource = new CancellationTokenSource( TimeSpan.FromSeconds(5)); using var httpClient = _httpClientFactory.CreateClient(); try { var response = await httpClient.PostAsync( new Uri(new Uri(backend.Endpoint), uri), content, cancellationTokenSource.Token); response.EnsureSuccessStatusCode(); } catch (Exception exception) { _logger.LogError( exception, $"Failed to initiate scan against {backend.Id}"); return false; } return true; } public async Task QueueFileScan( ScanBackend backend, string fileName, Stream fileStream, string callbackUrl) { return await QueueScan(backend, "/scan/file", new MultipartFormDataContent { {new StringContent(callbackUrl), nameof(FileRequest.CallbackUrl)}, {new StreamContent(fileStream), nameof(FileRequest.InputFile), fileName} }); } public async Task QueueUrlScan( ScanBackend backend, string url, string callbackUrl) { return await QueueScan(backend, "/scan/url", new MultipartFormDataContent { {new StringContent(callbackUrl), nameof(UrlRequest.CallbackUrl)}, {new StringContent(url), nameof(UrlRequest.InputUrl)} }); } } }