Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integrations support for results and task cancellation #109

Merged
Prev Previous commit
Next Next commit
Enh: Aircrack integration support for new contract
  • Loading branch information
Krzysztofz01 committed Oct 26, 2022
commit 56117fc85ea42e9e8db687820790cbaccaa0d612
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using AccessPointMap.Application.Integration.Core;

namespace AccessPointMap.Application.Integration.Aircrackng
{
internal class AircrackngIntegrationError : IntegrationError
{
protected AircrackngIntegrationError(string message) : base(message) { }

public static AircrackngIntegrationError UploadedCsvFileIsNull => new("The provided CSV file can not be accessed.");
public static AircrackngIntegrationError UploadedPcapFileIsNull => new("The provided CAP/PCAP file can not be accessed.");
public static AircrackngIntegrationError UploadedFileHasInvalidFormat => new("The provided file format is not matching the requirements.");
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
using AccessPointMap.Application.Integration.Aircrackng.Models;
using AccessPointMap.Application.Abstraction;
using AccessPointMap.Application.Integration.Aircrackng.Models;
using AccessPointMap.Application.Integration.Core;
using AccessPointMap.Application.Integration.Core.Exceptions;
using AccessPointMap.Application.Oui.Core;
using AccessPointMap.Application.Pcap.Core;
using AccessPointMap.Domain.AccessPoints;
using AccessPointMap.Domain.Core.Exceptions;
using AccessPointMap.Infrastructure.Core.Abstraction;
using CsvHelper;
using System;
Expand All @@ -12,6 +14,7 @@
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;

namespace AccessPointMap.Application.Integration.Aircrackng
Expand All @@ -36,54 +39,91 @@ public AircrackngIntegrationService(
IPcapParsingService pcapParsingService,
IOuiLookupService ouiLookupService) : base(unitOfWork, scopeWrapperService, pcapParsingService, ouiLookupService) { }


public async Task Handle(IIntegrationCommand command)
public async Task<Result> HandleCommandAsync(IIntegrationCommand command, CancellationToken cancellationToken = default)
{
switch (command)
try
{
case Commands.CreateAccessPointsFromCsvFile cmd: await HandleCommand(cmd); break;
case Commands.CreatePacketsFromPcapFile cmd: await HandleCommand(cmd); break;

default: throw new IntegrationException($"This command is not supported by the {IntegrationName} integration.");
return command switch
{
Commands.CreateAccessPointsFromCsvFile cmd => await HandleCommand(cmd, cancellationToken),
Commands.CreatePacketsFromPcapFile cmd => await HandleCommand(cmd, cancellationToken),
_ => throw new IntegrationException($"This command is not supported by the {IntegrationName} integration."),
};
}
catch (DomainException ex)
{
return Result.Failure(IntegrationError.FromDomainException(ex));
}
catch (IntegrationException ex)
{
return Result.Failure(IntegrationError.FromIntegrationException(ex));
}
catch (TaskCanceledException)
{
throw;
}
catch
{
throw;
}
}

public Task<object> Query(IIntegrationQuery query)
public async Task<Result<object>> HandleQueryAsync(IIntegrationQuery query, CancellationToken cancellationToken = default)
{
switch (query)
try
{
return query switch
{
_ => throw new IntegrationException($"This query is not supported by the {IntegrationName} integration.")
};
}
catch (DomainException ex)
{
return await Task.FromResult(Result.Failure(IntegrationError.FromDomainException(ex)));
}
catch (IntegrationException ex)
{
return await Task.FromResult(Result.Failure(IntegrationError.FromIntegrationException(ex)));
}
catch (TaskCanceledException)
{
default: throw new IntegrationException($"This query is not supported by the {IntegrationName} integration.");
throw;
}
catch
{
throw;
}
}

private async Task HandleCommand(Commands.CreatePacketsFromPcapFile cmd)
private async Task<Result> HandleCommand(Commands.CreatePacketsFromPcapFile cmd, CancellationToken cancellationToken = default)
{
if (cmd.ScanPcapFile is null)
throw new ArgumentNullException(nameof(cmd));
return Result.Failure(AircrackngIntegrationError.UploadedPcapFileIsNull);

if (Path.GetExtension(cmd.ScanPcapFile.FileName).ToLower() != ".cap")
throw new ArgumentNullException(nameof(cmd));
return Result.Failure(AircrackngIntegrationError.UploadedFileHasInvalidFormat);

// TODO: Pass CancellationToken to the method
var packetMap = await PcapParsingService.MapPacketsToMacAddressesAsync(cmd.ScanPcapFile);
var packetMap = await PcapParsingService.MapPacketsToMacAddressesAsync(cmd.ScanPcapFile, cancellationToken);

foreach (var map in packetMap)
{
await CreateAccessPointPackets(map.Key, map.Value);
await CreateAccessPointPackets(map.Key, map.Value, cancellationToken);
}

await UnitOfWork.Commit();
await UnitOfWork.Commit(cancellationToken);

return Result.Success();
}

private async Task HandleCommand(Commands.CreateAccessPointsFromCsvFile cmd)
private async Task<Result> HandleCommand(Commands.CreateAccessPointsFromCsvFile cmd, CancellationToken cancellationToken = default)
{
if (cmd.ScanCsvFile is null)
throw new ArgumentNullException(nameof(cmd));
return Result.Failure(AircrackngIntegrationError.UploadedCsvFileIsNull);

if (Path.GetExtension(cmd.ScanCsvFile.FileName).ToLower() != ".csv")
throw new ArgumentNullException(nameof(cmd));
return Result.Failure(AircrackngIntegrationError.UploadedFileHasInvalidFormat);

var accessPoints = ParseCsvAccessPointScanFile(cmd.ScanCsvFile.OpenReadStream());
var accessPoints = ParseCsvAccessPointScanFile(cmd.ScanCsvFile.OpenReadStream(), cancellationToken);
var runRecordGroups = GroupAccessPointsByRun(accessPoints);

foreach (var runGroup in runRecordGroups)
Expand All @@ -92,21 +132,22 @@ private async Task HandleCommand(Commands.CreateAccessPointsFromCsvFile cmd)

foreach (var record in runGroup.Value)
{
// TODO: Pass the CancellationToken to the repository method
if (await UnitOfWork.AccessPointRepository.ExistsAsync(record.Bssid))
if (await UnitOfWork.AccessPointRepository.ExistsAsync(record.Bssid, cancellationToken))
{
await CreateAccessPointStamp(record, runIdentifier);
await CreateAccessPointStamp(record, runIdentifier, cancellationToken);
continue;
}

await CreateAccessPoint(record, runIdentifier);
await CreateAccessPoint(record, runIdentifier, cancellationToken);
}
}

await UnitOfWork.Commit();
await UnitOfWork.Commit(cancellationToken);

return Result.Success();
}

private async Task CreateAccessPoint(AccessPointRecord record, Guid? runIdentifier)
private async Task CreateAccessPoint(AccessPointRecord record, Guid? runIdentifier, CancellationToken cancellationToken = default)
{
var accessPoint = AccessPoint.Factory.Create(new Events.V1.AccessPointCreated
{
Expand All @@ -125,8 +166,7 @@ private async Task CreateAccessPoint(AccessPointRecord record, Guid? runIdentifi
RunIdentifier = runIdentifier
});

// TODO: Pass CancellationToken to the method
var manufacturer = await OuiLookupService.GetManufacturerNameAsync(accessPoint.Bssid);
var manufacturer = await OuiLookupService.GetManufacturerNameAsync(accessPoint.Bssid, cancellationToken);

accessPoint.Apply(new Events.V1.AccessPointManufacturerChanged
{
Expand All @@ -141,14 +181,12 @@ private async Task CreateAccessPoint(AccessPointRecord record, Guid? runIdentifi
Content = SerializeRawAccessPointRecord(record)
});

// TODO: Pass the CancellationToken to the repository method
await UnitOfWork.AccessPointRepository.AddAsync(accessPoint);
await UnitOfWork.AccessPointRepository.AddAsync(accessPoint, cancellationToken);
}

private async Task CreateAccessPointStamp(AccessPointRecord record, Guid? runIdentifier)
private async Task CreateAccessPointStamp(AccessPointRecord record, Guid? runIdentifier, CancellationToken cancellationToken = default)
{
// TODO: Pass the CancellationToken to the repository method
var accessPoint = await UnitOfWork.AccessPointRepository.GetAsync(record.Bssid);
var accessPoint = await UnitOfWork.AccessPointRepository.GetAsync(record.Bssid, cancellationToken);

accessPoint.Apply(new Events.V1.AccessPointStampCreated
{
Expand All @@ -175,16 +213,16 @@ private async Task CreateAccessPointStamp(AccessPointRecord record, Guid? runIde
});
}

private async Task CreateAccessPointPackets(string bssid, IEnumerable<Packet> packets)
private async Task CreateAccessPointPackets(string bssid, IEnumerable<Packet> packets, CancellationToken cancellationToken = default)
{
// TODO: Pass the CancellationToken to the repository method
if (!await UnitOfWork.AccessPointRepository.ExistsAsync(bssid)) return;
if (!await UnitOfWork.AccessPointRepository.ExistsAsync(bssid, cancellationToken)) return;

// TODO: Pass the CancellationToken to the repository method
var accessPoint = await UnitOfWork.AccessPointRepository.GetAsync(bssid);
var accessPoint = await UnitOfWork.AccessPointRepository.GetAsync(bssid, cancellationToken);

foreach (var packet in packets)
{
cancellationToken.ThrowIfCancellationRequested();

accessPoint.Apply(new Events.V1.AccessPointPacketCreated
{
Id = accessPoint.Id,
Expand Down Expand Up @@ -242,7 +280,7 @@ private static string SerializeRawAccessPointRecord(AccessPointRecord record)
});
}

private static IEnumerable<AccessPointRecord> ParseCsvAccessPointScanFile(Stream csvFileStream)
private static IEnumerable<AccessPointRecord> ParseCsvAccessPointScanFile(Stream csvFileStream, CancellationToken cancellationToken = default)
{
const string _allowedType = "AP";

Expand All @@ -254,6 +292,8 @@ private static IEnumerable<AccessPointRecord> ParseCsvAccessPointScanFile(Stream

while (csv.Read())
{
cancellationToken.ThrowIfCancellationRequested();

// TODO: Some SSID'S are containing comma's which are confusing the CsvHelper parser
// The current solution is to skip all invalid rows.
AccessPointRecord record = null;
Expand Down