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;
|
||||||
using System.ComponentModel.DataAnnotations;
|
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)
|
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
|
||||||
{
|
{
|
||||||
var uri = (Uri) value;
|
var uri = (Uri) value;
|
||||||
|
|
||||||
if (uri == null || !uri.IsAbsoluteUri || uri.Scheme != "http" && uri.Scheme != "https")
|
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;
|
return ValidationResult.Success;
|
||||||
}
|
}
|
@ -1,9 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using MalwareMultiScan.Api.Attributes;
|
||||||
|
using MalwareMultiScan.Api.Data.Models;
|
||||||
using MalwareMultiScan.Api.Services;
|
using MalwareMultiScan.Api.Services;
|
||||||
using MalwareMultiScan.Shared.Attributes;
|
|
||||||
using MalwareMultiScan.Shared.Data.Responses;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
@ -16,13 +15,13 @@ namespace MalwareMultiScan.Api.Controllers
|
|||||||
{
|
{
|
||||||
private readonly ScanResultService _scanResultService;
|
private readonly ScanResultService _scanResultService;
|
||||||
|
|
||||||
public QueueController( ScanResultService scanResultService)
|
public QueueController(ScanResultService scanResultService)
|
||||||
{
|
{
|
||||||
_scanResultService = scanResultService;
|
_scanResultService = scanResultService;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("file")]
|
[HttpPost("file")]
|
||||||
[ProducesResponseType(typeof(ResultResponse), StatusCodes.Status201Created)]
|
[ProducesResponseType(typeof(ScanResult), StatusCodes.Status201Created)]
|
||||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||||
public async Task<IActionResult> ScanFile([FromForm] IFormFile file)
|
public async Task<IActionResult> ScanFile([FromForm] IFormFile file)
|
||||||
{
|
{
|
||||||
@ -31,7 +30,9 @@ namespace MalwareMultiScan.Api.Controllers
|
|||||||
string storedFileId;
|
string storedFileId;
|
||||||
|
|
||||||
await using (var uploadFileStream = file.OpenReadStream())
|
await using (var uploadFileStream = file.OpenReadStream())
|
||||||
|
{
|
||||||
storedFileId = await _scanResultService.StoreFile(file.Name, uploadFileStream);
|
storedFileId = await _scanResultService.StoreFile(file.Name, uploadFileStream);
|
||||||
|
}
|
||||||
|
|
||||||
await _scanResultService.QueueUrlScan(result, Url.Action("Index", "Download", new {id = storedFileId},
|
await _scanResultService.QueueUrlScan(result, Url.Action("Index", "Download", new {id = storedFileId},
|
||||||
Request.Scheme, Request.Host.Value));
|
Request.Scheme, Request.Host.Value));
|
||||||
@ -41,9 +42,9 @@ namespace MalwareMultiScan.Api.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("url")]
|
[HttpPost("url")]
|
||||||
[ProducesResponseType(typeof(ResultResponse), StatusCodes.Status201Created)]
|
[ProducesResponseType(typeof(ScanResult), StatusCodes.Status201Created)]
|
||||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
[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();
|
var result = await _scanResultService.CreateScanResult();
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MalwareMultiScan.Api.Data.Models;
|
using MalwareMultiScan.Api.Data.Models;
|
||||||
using MalwareMultiScan.Api.Services;
|
using MalwareMultiScan.Api.Services;
|
||||||
using MalwareMultiScan.Shared.Data.Responses;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
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>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\MalwareMultiScan.Backends\MalwareMultiScan.Backends.csproj" />
|
||||||
<ProjectReference Include="..\MalwareMultiScan.Shared\MalwareMultiScan.Shared.csproj" />
|
<ProjectReference Include="..\MalwareMultiScan.Shared\MalwareMultiScan.Shared.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using EasyNetQ;
|
using EasyNetQ;
|
||||||
using MalwareMultiScan.Shared.Data.Messages;
|
using MalwareMultiScan.Backends.Messages;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace MalwareMultiScan.Api.Services
|
namespace MalwareMultiScan.Api.Services
|
||||||
{
|
{
|
||||||
@ -12,22 +13,32 @@ namespace MalwareMultiScan.Api.Services
|
|||||||
private readonly IBus _bus;
|
private readonly IBus _bus;
|
||||||
private readonly IConfiguration _configuration;
|
private readonly IConfiguration _configuration;
|
||||||
private readonly ScanResultService _scanResultService;
|
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;
|
_bus = bus;
|
||||||
_configuration = configuration;
|
_configuration = configuration;
|
||||||
_scanResultService = scanResultService;
|
_scanResultService = scanResultService;
|
||||||
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task StartAsync(CancellationToken cancellationToken)
|
public Task StartAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
_bus.Receive<ScanResultMessage>(_configuration.GetValue<string>("ResultsSubscriptionId"), async message =>
|
_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(
|
await _scanResultService.UpdateScanResultForBackend(
|
||||||
message.Id, message.Backend, true, true, message.Threats);
|
message.Id, message.Backend, true, true, message.Threats);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
_logger.LogInformation(
|
||||||
|
"Started hosted service for receiving scan results");
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,6 +46,9 @@ namespace MalwareMultiScan.Api.Services
|
|||||||
{
|
{
|
||||||
_bus.Dispose();
|
_bus.Dispose();
|
||||||
|
|
||||||
|
_logger.LogInformation(
|
||||||
|
"Stopped hosted service for receiving scan results");
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,9 @@ using System.Threading.Tasks;
|
|||||||
using EasyNetQ;
|
using EasyNetQ;
|
||||||
using MalwareMultiScan.Api.Data.Configuration;
|
using MalwareMultiScan.Api.Data.Configuration;
|
||||||
using MalwareMultiScan.Api.Data.Models;
|
using MalwareMultiScan.Api.Data.Models;
|
||||||
using MalwareMultiScan.Shared.Data.Messages;
|
using MalwareMultiScan.Backends.Messages;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using YamlDotNet.Serialization;
|
using YamlDotNet.Serialization;
|
||||||
using YamlDotNet.Serialization.NamingConventions;
|
using YamlDotNet.Serialization.NamingConventions;
|
||||||
|
|
||||||
@ -14,10 +15,12 @@ namespace MalwareMultiScan.Api.Services
|
|||||||
public class ScanBackendService
|
public class ScanBackendService
|
||||||
{
|
{
|
||||||
private readonly IBus _bus;
|
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;
|
_bus = bus;
|
||||||
|
_logger = logger;
|
||||||
|
|
||||||
var configurationPath = configuration.GetValue<string>("BackendsConfiguration");
|
var configurationPath = configuration.GetValue<string>("BackendsConfiguration");
|
||||||
|
|
||||||
@ -37,6 +40,9 @@ namespace MalwareMultiScan.Api.Services
|
|||||||
|
|
||||||
public async Task QueueUrlScan(ScanResult result, ScanBackend backend, string fileUrl)
|
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
|
await _bus.SendAsync(backend.Id, new ScanRequestMessage
|
||||||
{
|
{
|
||||||
Id = result.Id,
|
Id = result.Id,
|
||||||
|
@ -1,13 +1,7 @@
|
|||||||
using System;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MalwareMultiScan.Api.Data.Configuration;
|
|
||||||
using MalwareMultiScan.Api.Data.Models;
|
using MalwareMultiScan.Api.Data.Models;
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using MongoDB.Bson;
|
using MongoDB.Bson;
|
||||||
using MongoDB.Driver;
|
using MongoDB.Driver;
|
||||||
using MongoDB.Driver.GridFS;
|
using MongoDB.Driver.GridFS;
|
||||||
@ -17,9 +11,9 @@ namespace MalwareMultiScan.Api.Services
|
|||||||
public class ScanResultService
|
public class ScanResultService
|
||||||
{
|
{
|
||||||
private const string CollectionName = "ScanResults";
|
private const string CollectionName = "ScanResults";
|
||||||
|
private readonly GridFSBucket _bucket;
|
||||||
|
|
||||||
private readonly IMongoCollection<ScanResult> _collection;
|
private readonly IMongoCollection<ScanResult> _collection;
|
||||||
private readonly GridFSBucket _bucket;
|
|
||||||
|
|
||||||
private readonly ScanBackendService _scanBackendService;
|
private readonly ScanBackendService _scanBackendService;
|
||||||
|
|
||||||
|
@ -18,15 +18,12 @@ namespace MalwareMultiScan.Backends.Backends.Abstracts
|
|||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual Regex MatchRegex { get; }
|
protected abstract Regex MatchRegex { get; }
|
||||||
protected virtual string BackendPath { get; }
|
protected abstract string BackendPath { get; }
|
||||||
protected virtual bool ParseStdErr { get; }
|
protected virtual bool ParseStdErr { get; }
|
||||||
protected virtual bool ThrowOnNonZeroExitCode { get; } = true;
|
protected virtual bool ThrowOnNonZeroExitCode { get; } = true;
|
||||||
|
|
||||||
protected virtual string GetBackendArguments(string path)
|
protected abstract string GetBackendArguments(string path);
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override async Task<string[]> ScanAsync(string path, CancellationToken cancellationToken)
|
public override async Task<string[]> ScanAsync(string path, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
@ -3,23 +3,21 @@ using System.IO;
|
|||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MalwareMultiScan.Shared.Interfaces;
|
using MalwareMultiScan.Backends.Interfaces;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
namespace MalwareMultiScan.Backends.Backends.Abstracts
|
namespace MalwareMultiScan.Backends.Backends.Abstracts
|
||||||
{
|
{
|
||||||
public abstract class AbstractScanBackend : IScanBackend
|
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)
|
public abstract Task<string[]> ScanAsync(string path, CancellationToken cancellationToken);
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<string[]> ScanAsync(Uri uri, CancellationToken cancellationToken)
|
public async Task<string[]> ScanAsync(Uri uri, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
using var httpClient = new HttpClient();
|
using var httpClient = new HttpClient();
|
||||||
|
|
||||||
await using var uriStream = await httpClient.GetStreamAsync(uri);
|
await using var uriStream = await httpClient.GetStreamAsync(uri);
|
||||||
|
|
||||||
return await ScanAsync(uriStream, cancellationToken);
|
return await ScanAsync(uriStream, cancellationToken);
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using MalwareMultiScan.Backends.Backends.Abstracts;
|
using MalwareMultiScan.Backends.Backends.Abstracts;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
@ -2,7 +2,7 @@ using System;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MalwareMultiScan.Shared.Interfaces;
|
using MalwareMultiScan.Backends.Interfaces;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
namespace MalwareMultiScan.Backends.Backends.Implementations
|
namespace MalwareMultiScan.Backends.Backends.Implementations
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
namespace MalwareMultiScan.Shared.Data.Enums
|
namespace MalwareMultiScan.Backends.Enums
|
||||||
{
|
{
|
||||||
public enum BackendType
|
public enum BackendType
|
||||||
{
|
{
|
@ -1,11 +1,11 @@
|
|||||||
using System;
|
using System;
|
||||||
using MalwareMultiScan.Backends.Backends.Implementations;
|
using MalwareMultiScan.Backends.Backends.Implementations;
|
||||||
using MalwareMultiScan.Shared.Data.Enums;
|
using MalwareMultiScan.Backends.Enums;
|
||||||
using MalwareMultiScan.Shared.Interfaces;
|
using MalwareMultiScan.Backends.Interfaces;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace MalwareMultiScan.Scanner.Extensions
|
namespace MalwareMultiScan.Backends.Extensions
|
||||||
{
|
{
|
||||||
public static class ServiceCollectionExtensions
|
public static class ServiceCollectionExtensions
|
||||||
{
|
{
|
||||||
@ -13,7 +13,7 @@ namespace MalwareMultiScan.Scanner.Extensions
|
|||||||
{
|
{
|
||||||
using var provider = services.BuildServiceProvider();
|
using var provider = services.BuildServiceProvider();
|
||||||
|
|
||||||
var logger = provider.GetService<ILogger>();
|
var logger = provider.GetService<ILogger<IScanBackend>>();
|
||||||
|
|
||||||
services.AddSingleton<IScanBackend>(type switch
|
services.AddSingleton<IScanBackend>(type switch
|
||||||
{
|
{
|
@ -4,7 +4,7 @@ using System.Threading;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
namespace MalwareMultiScan.Shared.Interfaces
|
namespace MalwareMultiScan.Backends.Interfaces
|
||||||
{
|
{
|
||||||
public interface IScanBackend
|
public interface IScanBackend
|
||||||
{
|
{
|
@ -8,4 +8,8 @@
|
|||||||
<ProjectReference Include="..\MalwareMultiScan.Shared\MalwareMultiScan.Shared.csproj" />
|
<ProjectReference Include="..\MalwareMultiScan.Shared\MalwareMultiScan.Shared.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.9" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace MalwareMultiScan.Shared.Data.Messages
|
namespace MalwareMultiScan.Backends.Messages
|
||||||
{
|
{
|
||||||
public class ScanRequestMessage
|
public class ScanRequestMessage
|
||||||
{
|
{
|
@ -1,4 +1,4 @@
|
|||||||
namespace MalwareMultiScan.Shared.Data.Messages
|
namespace MalwareMultiScan.Backends.Messages
|
||||||
{
|
{
|
||||||
public class ScanResultMessage
|
public class ScanResultMessage
|
||||||
{
|
{
|
@ -13,4 +13,8 @@
|
|||||||
<ProjectReference Include="..\MalwareMultiScan.Backends\MalwareMultiScan.Backends.csproj" />
|
<ProjectReference Include="..\MalwareMultiScan.Backends\MalwareMultiScan.Backends.csproj" />
|
||||||
<ProjectReference Include="..\MalwareMultiScan.Shared\MalwareMultiScan.Shared.csproj" />
|
<ProjectReference Include="..\MalwareMultiScan.Shared\MalwareMultiScan.Shared.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<_ContentIncludedByDefault Remove="Properties\launchSettings.json" />
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MalwareMultiScan.Scanner.Extensions;
|
using MalwareMultiScan.Backends.Enums;
|
||||||
using MalwareMultiScan.Shared.Data.Enums;
|
using MalwareMultiScan.Backends.Extensions;
|
||||||
|
using MalwareMultiScan.Scanner.Services;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
@ -14,7 +15,7 @@ namespace MalwareMultiScan.Scanner
|
|||||||
await Host.CreateDefaultBuilder(args)
|
await Host.CreateDefaultBuilder(args)
|
||||||
.ConfigureAppConfiguration(configure =>
|
.ConfigureAppConfiguration(configure =>
|
||||||
{
|
{
|
||||||
configure.AddJsonFile("settings.json");
|
configure.AddJsonFile("appsettings.json");
|
||||||
configure.AddEnvironmentVariables();
|
configure.AddEnvironmentVariables();
|
||||||
})
|
})
|
||||||
.ConfigureServices((context, services) =>
|
.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;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using EasyNetQ;
|
using EasyNetQ;
|
||||||
using MalwareMultiScan.Shared.Data.Messages;
|
using MalwareMultiScan.Backends.Interfaces;
|
||||||
using MalwareMultiScan.Shared.Interfaces;
|
using MalwareMultiScan.Backends.Messages;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Logging;
|
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 IConfiguration _configuration;
|
||||||
private readonly ILogger<ScanHostedService> _logger;
|
private readonly ILogger<ScanHostedService> _logger;
|
||||||
private readonly IScanBackend _scanBackend;
|
|
||||||
|
|
||||||
private IBus _bus;
|
private IBus _bus;
|
||||||
|
|
||||||
public ScanHostedService(ILogger<ScanHostedService> logger, IConfiguration configuration, IScanBackend scanBackend)
|
public ScanHostedService(ILogger<ScanHostedService> logger, IConfiguration configuration, IScanBackend backend)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_configuration = configuration;
|
_configuration = configuration;
|
||||||
_scanBackend = scanBackend;
|
_backend = backend;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task StartAsync(CancellationToken cancellationToken)
|
public Task StartAsync(CancellationToken cancellationToken)
|
||||||
@ -30,38 +30,48 @@ namespace MalwareMultiScan.Scanner
|
|||||||
_bus = RabbitHutch.CreateBus(
|
_bus = RabbitHutch.CreateBus(
|
||||||
_configuration.GetConnectionString("RabbitMQ"));
|
_configuration.GetConnectionString("RabbitMQ"));
|
||||||
|
|
||||||
_bus.Receive<ScanRequestMessage>(
|
_bus.Receive<ScanRequestMessage>(_backend.Id, Scan);
|
||||||
_scanBackend.Id, Scan);
|
|
||||||
|
_logger.LogInformation(
|
||||||
|
$"Started scan hosting service for the backend {_backend.Id}");
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Task StopAsync(CancellationToken cancellationToken)
|
public Task StopAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
_bus.Dispose();
|
_bus.Dispose();
|
||||||
|
|
||||||
|
_logger.LogInformation(
|
||||||
|
$"Stopped scan hosting service for the backend {_backend.Id}");
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Scan(ScanRequestMessage message)
|
private async Task Scan(ScanRequestMessage message)
|
||||||
{
|
{
|
||||||
_logger.LogInformation(
|
_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(
|
var cancellationTokenSource = new CancellationTokenSource(
|
||||||
TimeSpan.FromSeconds(_configuration.GetValue<int>("MaxScanningTime")));
|
TimeSpan.FromSeconds(_configuration.GetValue<int>("MaxScanningTime")));
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _bus.SendAsync(_configuration.GetValue<string>("ResultsSubscriptionId"), new ScanResultMessage
|
var result = new ScanResultMessage
|
||||||
{
|
{
|
||||||
Id = message.Id,
|
Id = message.Id,
|
||||||
Backend = _scanBackend.Id,
|
Backend = _backend.Id,
|
||||||
|
|
||||||
Threats = await _scanBackend.ScanAsync(
|
Threats = await _backend.ScanAsync(
|
||||||
message.Uri, cancellationTokenSource.Token)
|
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)
|
catch (Exception exception)
|
||||||
{
|
{
|
@ -9,9 +9,7 @@
|
|||||||
|
|
||||||
"BackendType": "Dummy",
|
"BackendType": "Dummy",
|
||||||
|
|
||||||
"MaxWorkers": 5,
|
|
||||||
"MaxScanningTime": 60,
|
"MaxScanningTime": 60,
|
||||||
|
|
||||||
"ResultsSubscriptionId": "mms.results",
|
"ResultsSubscriptionId": "mms.results",
|
||||||
|
|
||||||
"ConnectionStrings": {
|
"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
|
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}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MalwareMultiScan.Backends", "MalwareMultiScan.Backends\MalwareMultiScan.Backends.csproj", "{382B49AC-0FFA-44FC-875D-9D4692DDC05D}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MalwareMultiScan.Api", "MalwareMultiScan.Api\MalwareMultiScan.Api.csproj", "{7B63B897-D390-4617-821F-F96799CBA2F4}"
|
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
|
Release|Any CPU = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
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.ActiveCfg = Debug|Any CPU
|
||||||
{382B49AC-0FFA-44FC-875D-9D4692DDC05D}.Debug|Any CPU.Build.0 = 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
|
{382B49AC-0FFA-44FC-875D-9D4692DDC05D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
Loading…
x
Reference in New Issue
Block a user