diff --git a/dotnet/Vaas/src/Vaas/Messages/Detection.cs b/dotnet/Vaas/src/Vaas/Messages/Detection.cs new file mode 100644 index 00000000..bf3ae184 --- /dev/null +++ b/dotnet/Vaas/src/Vaas/Messages/Detection.cs @@ -0,0 +1,15 @@ +using System.Text.Json.Serialization; + +namespace Vaas.Messages; + +public class Detection +{ + [JsonPropertyName("engine")] + public int? Engine { get; init; } + + [JsonPropertyName("fileName")] + public string FileName { get; init; } + + [JsonPropertyName("virus")] + public string Virus { get; init; } +} \ No newline at end of file diff --git a/dotnet/Vaas/src/Vaas/Messages/LibMagic.cs b/dotnet/Vaas/src/Vaas/Messages/LibMagic.cs new file mode 100644 index 00000000..42c29583 --- /dev/null +++ b/dotnet/Vaas/src/Vaas/Messages/LibMagic.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace Vaas.Messages; + +public class LibMagic +{ + [JsonPropertyName("fileType")] + public string FileType { get; init; } + + [JsonPropertyName("mimeType")] + public string MimeType { get; init; } +} \ No newline at end of file diff --git a/dotnet/Vaas/src/Vaas/Messages/VerdictResponse.cs b/dotnet/Vaas/src/Vaas/Messages/VerdictResponse.cs index a48b392e..6e0cd4d0 100644 --- a/dotnet/Vaas/src/Vaas/Messages/VerdictResponse.cs +++ b/dotnet/Vaas/src/Vaas/Messages/VerdictResponse.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Text.Json.Serialization; using CommunityToolkit.Diagnostics; @@ -32,9 +33,14 @@ public VerdictResponse(string sha256, Verdict verdict) [JsonPropertyName("upload_token")] public string? UploadToken { get; init; } + + [JsonPropertyName("detections")] + public List? Detections { get; init; } + + [JsonPropertyName("libMagic")] + public LibMagic? LibMagic { get; init; } [MemberNotNullWhen(true, nameof(Sha256), nameof(Guid))] public bool IsValid => !string.IsNullOrWhiteSpace(Sha256) && !string.IsNullOrWhiteSpace(Guid); - } \ No newline at end of file diff --git a/dotnet/Vaas/src/Vaas/VaasVerdict.cs b/dotnet/Vaas/src/Vaas/VaasVerdict.cs index 8b6a032f..d11822a1 100644 --- a/dotnet/Vaas/src/Vaas/VaasVerdict.cs +++ b/dotnet/Vaas/src/Vaas/VaasVerdict.cs @@ -1,3 +1,5 @@ +using System.Collections.Generic; + namespace Vaas.Messages; public class VaasVerdict @@ -6,8 +8,12 @@ public VaasVerdict(VerdictResponse verdictResponse) { Sha256 = verdictResponse.Sha256 ?? ""; Verdict = verdictResponse.Verdict; + Detections = verdictResponse.Detections; + LibMagic = verdictResponse.LibMagic; } public string Sha256 { get; init; } public Verdict Verdict { get; init; } + public List? Detections { get; init; } + public LibMagic? LibMagic { get; init; } } diff --git a/dotnet/Vaas/test/Vaas.Test/IntegrationTests.cs b/dotnet/Vaas/test/Vaas.Test/IntegrationTests.cs index a5ae85b5..68598d06 100644 --- a/dotnet/Vaas/test/Vaas.Test/IntegrationTests.cs +++ b/dotnet/Vaas/test/Vaas.Test/IntegrationTests.cs @@ -256,6 +256,7 @@ private async Task AuthenticateWithCredentials() { "VerdictAsAService:Credentials:GrantType", "ClientCredentials" }, { "VerdictAsAService:Credentials:ClientId", AuthenticationEnvironment.ClientId }, { "VerdictAsAService:Credentials:ClientSecret", AuthenticationEnvironment.ClientSecret }, + { "VerdictAsAService:UseCache", "false" } }); ServiceCollectionTools.Output(_output, services); var provider = services.BuildServiceProvider(); @@ -304,4 +305,36 @@ public async Task Connect_WithResourceOwnerPasswordGrantAuthenticator() var vaas = provider.GetRequiredService(); await vaas.Connect(CancellationToken.None); } + + [Fact] + public async Task ForStream_WithEicarUrl_ReturnsMaliciousWithDetectionsAndMimeType() + { + var vaas = await AuthenticateWithCredentials(); + var url = new Uri("https://secure.eicar.org/eicar.com.txt"); + var response = await _httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Get, url), CancellationToken.None); + var targetStream = await response.Content.ReadAsStreamAsync(); + + var verdict = await vaas.ForStreamAsync(targetStream, CancellationToken.None); + + Assert.Equal(Verdict.Malicious, verdict.Verdict); + Assert.NotNull(verdict.LibMagic); + Assert.NotNull(verdict.Detections); + Assert.Equal("text/plain", verdict.LibMagic.MimeType); + Assert.Contains(verdict.Detections, detection => detection.Virus == "EICAR_TEST_FILE"); + } + + [Fact] + public async Task ForUrl_WithEicarUrl_ReturnsMaliciousWithDetectionAndMimeType() + { + var vaas = await AuthenticateWithCredentials(); + var uri = new Uri("https://secure.eicar.org/eicar.com"); + + var verdict = await vaas.ForUrlAsync(uri, CancellationToken.None); + + Assert.Equal(Verdict.Malicious, verdict.Verdict); + Assert.NotNull(verdict.LibMagic); + Assert.NotNull(verdict.Detections); + Assert.Equal("text/plain", verdict.LibMagic.MimeType); + Assert.Contains(verdict.Detections, detection => detection.Virus == "EICAR_TEST_FILE"); + } } \ No newline at end of file