diff --git a/.gitignore b/.gitignore index 1d233990b8b65a79da75dd14974ab365924e387b..5f106c031d5843d8053affb54921a4ef3da48dff 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ **/**notes.md nuget_api.txt nuget_local.sh +global.json private_notes/ IntegrationTests/certificates @@ -489,4 +490,4 @@ Temporary Items .apdisk deploy.sh -global.json \ No newline at end of file +global.json diff --git a/.reuse/dep5 b/.reuse/dep5 index a048dc1f3b8898df0e2e5e7eb62a10e31539569c..437d94957547891df850bd5d859e4788cafc67bc 100644 --- a/.reuse/dep5 +++ b/.reuse/dep5 @@ -2,7 +2,7 @@ Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Files: FitConnect/* BasicUnitTest/* E2ETest/* EncryptionTests/* IntegrationTests/* MockContainer/* FitConnect.sln test.Dockerfile Test.pdf version.sh FitConnect.sln.DotSettings - README.md CHANGELOG.md *.md Dockerfile nuget_upload.sh ConsoleAppExample/* + README.md CHANGELOG.md *.md Dockerfile nuget_upload.sh ConsoleAppExample/* global.json Copyright: 2022 FIT-Connect contributors License: EUPL-1.2 diff --git a/BasicUnitTest/BasicUnitTest.csproj b/BasicUnitTest/BasicUnitTest.csproj index 2df0bbf69eab0f5ec8186c55d05f63cbddc8817b..c892fc2e29f830cb55e99a9ad45ea039772b3b9a 100644 --- a/BasicUnitTest/BasicUnitTest.csproj +++ b/BasicUnitTest/BasicUnitTest.csproj @@ -8,13 +8,16 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="FluentAssertions" Version="6.7.0" /> - <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="6.0.0" /> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" /> - <PackageReference Include="Moq" Version="4.18.1" /> - <PackageReference Include="NUnit" Version="3.13.2" /> - <PackageReference Include="NUnit3TestAdapter" Version="4.0.0" /> - <PackageReference Include="coverlet.collector" Version="3.1.0" /> + <PackageReference Include="FluentAssertions" Version="6.8.0" /> + <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="7.0.0" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.1" /> + <PackageReference Include="Moq" Version="4.18.4" /> + <PackageReference Include="NUnit" Version="3.13.3" /> + <PackageReference Include="NUnit3TestAdapter" Version="4.3.1" /> + <PackageReference Include="coverlet.collector" Version="3.2.0"> + <PrivateAssets>all</PrivateAssets> + <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> + </PackageReference> </ItemGroup> <ItemGroup> diff --git a/BasicUnitTest/SecurityEventTokenTests.cs b/BasicUnitTest/SecurityEventTokenTests.cs index da9967d56c8c8a9068fb0655cc1b23ec0f41a10c..695ea083a39439d9fe7600a4f96d27594bafec4c 100644 --- a/BasicUnitTest/SecurityEventTokenTests.cs +++ b/BasicUnitTest/SecurityEventTokenTests.cs @@ -50,7 +50,7 @@ public class SecurityEventTokenTests { var securityEventToken = SecurityEventToken.FromJson(json); securityEventToken?.EventType.Should().Be(EventType.Reject); - securityEventToken?.Events?.RejectSubmissionEvent?.Problems[0].Type.Should() + securityEventToken?.Events?.RejectSubmissionEvent?.Problems![0].Type.Should() .Contain("authentication-tag-incorrect"); } diff --git a/ConsoleAppExample/ConsoleAppExample.csproj b/ConsoleAppExample/ConsoleAppExample.csproj index da7bcce36f4aa8f7618abe2b93a813b52b2f32f3..3d4acd306f8418e9913aab5f9c079f3e5ad78186 100644 --- a/ConsoleAppExample/ConsoleAppExample.csproj +++ b/ConsoleAppExample/ConsoleAppExample.csproj @@ -10,11 +10,11 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="FitConnect" Version="0.0.1-beta.2"/> - <PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.0"/> - <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0"/> - <PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0"/> - <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="6.0.0"/> + <PackageReference Include="FitConnect" Version="0.0.1-beta.2" /> + <PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" /> + <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" /> + <PackageReference Include="Microsoft.Extensions.Logging" Version="7.0.0" /> + <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="7.0.0" /> </ItemGroup> <ItemGroup> @@ -42,7 +42,7 @@ </ItemGroup> <ItemGroup> - <ProjectReference Include="..\FitConnect\FitConnect.csproj"/> + <ProjectReference Include="..\FitConnect\FitConnect.csproj" /> </ItemGroup> </Project> diff --git a/ConsoleAppExample/SenderDemo.cs b/ConsoleAppExample/SenderDemo.cs index 960f76bbf56e23e37a9580d5507926e15c8c27de..0dcb9f519a2dc941827516f2e3e46b7d9c95ba9d 100644 --- a/ConsoleAppExample/SenderDemo.cs +++ b/ConsoleAppExample/SenderDemo.cs @@ -13,6 +13,10 @@ public static class SenderDemo { var destinationId = config["FitConnect:Sender:DestinationId"]; var leikaKey = config["FitConnect:Sender:LeikaKey"]; + if (clientId == null || clientSecret == null || destinationId == null || leikaKey == null) { + logger.LogError("Missing configuration values"); + return; + } OutputHelper.PrintSender(); @@ -34,6 +38,11 @@ public static class SenderDemo { var destinationId = config["FitConnect:Sender:DestinationId"]; var leikaKey = config["FitConnect:Sender:LeikaKey"]; + if (clientId == null || clientSecret == null || destinationId == null || leikaKey == null) { + logger.LogError("Missing configuration values"); + return; + } + var encryption = new FitEncryption("", "", null); Dictionary<string, string>? encryptedAttachments = null; diff --git a/ConsoleAppExample/SubscriberDemo.cs b/ConsoleAppExample/SubscriberDemo.cs index 54ab8dd5591911653534c521e248290e5cd563b4..d69b4d47be32835cdf8cbbd9e7c3197e10c3c444 100644 --- a/ConsoleAppExample/SubscriberDemo.cs +++ b/ConsoleAppExample/SubscriberDemo.cs @@ -11,6 +11,10 @@ public static class SubscriberDemo { var privateKeyDecryption = config["FitConnect:Subscriber:PrivateKeyDecryption"]; var privateKeySigning = config["FitConnect:Subscriber:PrivateKeySigning"]; + if (clientId == null || clientSecret == null || privateKeyDecryption == null || privateKeySigning == null) { + logger.LogError("Missing configuration values"); + return; + } OutputHelper.PrintSubscriber(); diff --git a/E2ETest/E2ETest.csproj b/E2ETest/E2ETest.csproj index 974a92a07342e19b27e979c3c468d7658703bc45..e13dc61c9178f5adde85d250742a840c2a30e135 100644 --- a/E2ETest/E2ETest.csproj +++ b/E2ETest/E2ETest.csproj @@ -9,17 +9,23 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="FluentAssertions" Version="6.7.0"/> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0"/> - <PackageReference Include="NUnit" Version="3.13.3"/> - <PackageReference Include="NUnit3TestAdapter" Version="4.2.1"/> - <PackageReference Include="NUnit.Analyzers" Version="3.3.0"/> - <PackageReference Include="coverlet.collector" Version="3.1.2"/> + <PackageReference Include="FluentAssertions" Version="6.8.0" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.1" /> + <PackageReference Include="NUnit" Version="3.13.3" /> + <PackageReference Include="NUnit3TestAdapter" Version="4.3.1" /> + <PackageReference Include="NUnit.Analyzers" Version="3.5.0"> + <PrivateAssets>all</PrivateAssets> + <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> + </PackageReference> + <PackageReference Include="coverlet.collector" Version="3.2.0"> + <PrivateAssets>all</PrivateAssets> + <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> + </PackageReference> </ItemGroup> <ItemGroup> - <ProjectReference Include="..\FitConnect\FitConnect.csproj"/> - <ProjectReference Include="..\MockContainer\MockContainer.csproj"/> + <ProjectReference Include="..\FitConnect\FitConnect.csproj" /> + <ProjectReference Include="..\MockContainer\MockContainer.csproj" /> </ItemGroup> </Project> diff --git a/E2ETest/RejectSubmissionTest.cs b/E2ETest/RejectSubmissionTest.cs index 9450583232b20a17656e2b7527bcd328ef9eb2f9..f938284aa62c130f5c37cf68efc09a048ab815e6 100644 --- a/E2ETest/RejectSubmissionTest.cs +++ b/E2ETest/RejectSubmissionTest.cs @@ -8,8 +8,7 @@ namespace E2ETest; [Order(10)] public class RejectSubmissionTest : EndToEndTestBase { - private string _caseId = null!; - private string _submissionId = null!; + private SentSubmission _submission = null!; [Order(5)] [Test] @@ -40,20 +39,17 @@ public class RejectSubmissionTest : EndToEndTestBase { .WithAttachments(new Attachment("Test.pdf", "A simple PDF")) .Build(); - var submission = Sender.SendAsync(outgoing).Result; + _submission = Sender.SendAsync(outgoing).Result; - _caseId = submission.CaseId!; - _submissionId = submission.Id!; - - _caseId.Should().NotBeNull(); - _submissionId.Should().NotBeNull(); + _submission.CaseId.Should().NotBeNull(); + _submission.SubmissionId.Should().NotBeNull(); } [Test] [Order(20)] public void Sender_GetSubmissionState() { // Act - var status = Sender.GetStatusForSubmissionAsync(_caseId, Settings.DestinationId).Result; + var status = Sender.GetEventLogAsync(_submission.CaseId, Settings.DestinationId).Result; // Assert status.Count.Should().BeGreaterThan(0); @@ -65,7 +61,7 @@ public class RejectSubmissionTest : EndToEndTestBase { [Order(30)] public void Subscriber_GetSubmissionState() { // Act - var status = Subscriber.GetStatusForSubmissionAsync(_caseId, Settings.DestinationId).Result; + var status = Subscriber.GetEventLogAsync(_submission.CaseId, Settings.DestinationId).Result; // Assert status.Count.Should().BeGreaterThan(0); @@ -76,7 +72,8 @@ public class RejectSubmissionTest : EndToEndTestBase { [Test] [Order(40)] public void Reject_Submission() { - var subscriberWithSubmission = Subscriber.RequestSubmissionAsync(_submissionId).Result; + var subscriberWithSubmission = + Subscriber.RequestSubmissionAsync(_submission.SubmissionId).Result; var data = subscriberWithSubmission.GetDataString(); Logger.LogInformation("Data {Data}", data); @@ -87,15 +84,17 @@ public class RejectSubmissionTest : EndToEndTestBase { attachments.First().Filename.Should().Be("Test.pdf"); subscriberWithSubmission.RejectSubmissionAsync( - new Problems(Problems.ProblemTypeEnum.SchemaViolation, "") + new Problems(Problems.ProblemTypeEnum.SchemaViolation, ProblemDetail) ).Wait(); } + private const string ProblemDetail = "Reject submission test"; + [Test] [Order(50)] public void Sender_GetSubmissionState_AfterRejecting() { // Act - var status = Sender.GetStatusForSubmissionAsync(_caseId, Settings.DestinationId).Result; + var status = Sender.GetEventLogAsync(_submission.CaseId, Settings.DestinationId).Result; // Assert status.Count.Should().BeGreaterThan(0); @@ -105,6 +104,17 @@ public class RejectSubmissionTest : EndToEndTestBase { var rejection = status.First(s => s.EventType == EventType.Reject); rejection.Events?.RejectSubmissionEvent?.Problems.Should().NotBeNull(); - rejection.Events?.RejectSubmissionEvent?.Problems?.ForEach(p => Logger.LogWarning(p.Detail)); + rejection.Events?.RejectSubmissionEvent?.Problems?.ForEach(p => + Logger.LogWarning(p.Detail)); + } + + [Test] + [Order(60)] + public void Sender_GetStatus() { + var (status, problems) = + Sender.GetStatusForSubmissionAsync(_submission).Result; + + status.Should().Be(EventType.Reject); + problems!.Any(p => p.Detail == ProblemDetail).Should().BeTrue(); } } diff --git a/E2ETest/StraightForwardTest.cs b/E2ETest/StraightForwardTest.cs index 87cfd66c53151486e2ec23de6b3ec0f6d561ba16..3155bd6aa46eef899f84d24673b2dc1dea62f76b 100644 --- a/E2ETest/StraightForwardTest.cs +++ b/E2ETest/StraightForwardTest.cs @@ -1,3 +1,4 @@ +using System.Security.Authentication; using FitConnect; using FitConnect.Models; using FluentAssertions; @@ -8,8 +9,7 @@ namespace E2ETest; [Order(20)] [TestFixture] public class StraightForwardTest : EndToEndTestBase { - private string _caseId = null!; - private string _submissionId = null!; + private SentSubmission _submission = null!; [Order(10)] [Test] @@ -20,15 +20,20 @@ public class StraightForwardTest : EndToEndTestBase { .WithJsonData(@"{""data"":""value""}") .WithAttachments(new Attachment("Test.pdf", "Attachment #1"), new Attachment("Test.pdf", "Attachment #2")) + .WithAttachments(new Attachment("Test.pdf", "Attachment #3")) .Build(); - var submission = Sender.SendAsync(outgoing).Result; + _submission = Sender.SendAsync(outgoing).Result; - _caseId = submission.CaseId!; - _submissionId = submission.Id!; + _submission.Should().NotBeNull(); - _caseId.Should().NotBeNull(); - _submissionId.Should().NotBeNull(); + _submission.CaseId.Should().NotBeNull(); + _submission.SubmissionId.Should().NotBeNull(); + _submission.AuthenticationTags.Metadata.Should().NotBeNullOrWhiteSpace(); + _submission.AuthenticationTags.Data.Should().NotBeNullOrWhiteSpace(); + _submission.AuthenticationTags.Attachments!.All(item => + !(string.IsNullOrWhiteSpace(item.Value) || string.IsNullOrWhiteSpace(item.Key))) + .Should().BeTrue(); } [Order(11)] @@ -42,7 +47,7 @@ public class StraightForwardTest : EndToEndTestBase { var submission = Sender.SendAsync(outgoing).Result; var caseId = submission.CaseId!; - var submissionId = submission.Id!; + var submissionId = submission.SubmissionId!; caseId.Should().NotBeNull(); submissionId.Should().NotBeNull(); @@ -52,7 +57,18 @@ public class StraightForwardTest : EndToEndTestBase { [Order(20)] public void Sender_GetSubmissionState() { // Act - var status = Sender.GetStatusForSubmissionAsync(_caseId, Settings.DestinationId).Result; + var status = Sender.GetStatusForSubmissionAsync(_submission) + .Result; + + // Assert + status.Status.Should().Be(EventType.Submit); + } + + [Test] + [Order(21)] + public void Sender_GetEventLogAfterSubmit() { + // Act + var status = Sender.GetEventLogAsync(_submission.CaseId, Settings.DestinationId).Result; // Assert status.Count.Should().BeGreaterThan(0); @@ -64,7 +80,7 @@ public class StraightForwardTest : EndToEndTestBase { [Order(30)] public void Subscriber_GetSubmissionState() { // Act - var status = Subscriber.GetStatusForSubmissionAsync(_caseId, Settings.DestinationId).Result; + var status = Subscriber.GetEventLogAsync(_submission.CaseId, Settings.DestinationId).Result; // Assert status.Count.Should().BeGreaterThan(0); @@ -75,7 +91,8 @@ public class StraightForwardTest : EndToEndTestBase { [Test] [Order(40)] public void RequestSubmission() { - var subscriberWithSubmission = Subscriber.RequestSubmissionAsync(_submissionId).Result; + var subscriberWithSubmission = + Subscriber.RequestSubmissionAsync(_submission.SubmissionId).Result; var data = subscriberWithSubmission.GetDataString(); Logger.LogInformation("Data {Data}", data); @@ -83,18 +100,20 @@ public class StraightForwardTest : EndToEndTestBase { data.Should().Be(@"{""data"":""value""}"); var attachments = subscriberWithSubmission.GetAttachmentsAsync().Result.ToList(); - attachments.First().Filename.Should().Be("Test.pdf"); + attachments.TrueForAll(a => a.Filename == "Test.pdf"); attachments.TrueForAll(a => a.Description?.StartsWith("Attachment #") ?? false).Should() .BeTrue(); - + attachments.Count.Should().Be(3); + var size = File.ReadAllBytes("Test.pdf").Length; + attachments.ForEach(a => a.Content!.Length.Should().Be(size)); subscriberWithSubmission.AcceptSubmissionAsync().Wait(); } [Test] [Order(50)] - public void Sender_GetSubmissionState_AfterAccepting() { + public void Sender_GetEventLog_AfterAccepting() { // Act - var status = Sender.GetStatusForSubmissionAsync(_caseId, Settings.DestinationId).Result; + var status = Sender.GetEventLogAsync(_submission.CaseId, Settings.DestinationId).Result; // Assert status.Count.Should().BeGreaterThan(0); @@ -107,4 +126,43 @@ public class StraightForwardTest : EndToEndTestBase { status.ForEach( s => Logger.LogInformation("Status {When} {Event}", s.EventTime, s.EventType)); } + + [Test] + [Order(51)] + public void Sender_GetSubmissionState_AfterAccepting() { + var status = Sender.GetStatusForSubmissionAsync(_submission).Result; + + status.Status.Should().Be(EventType.Accept); + status.Problems.Should().BeNullOrEmpty(); + } + + [Test] + [Order(60)] + public void Sender_GetStatus_AfterAccepting() { + // Act + var (status, problems) = + Sender.GetStatusForSubmissionAsync(_submission).Result; + + // Assert + status.Should().Be(EventType.Accept); + } + + [Test] + [Order(61)] + public void Sender_GetStatusForSubmission_FailsOnManipulatedAuthenticationTags() { + var manipulated = new SentSubmission(_submission.SubmissionId, _submission.CaseId, + _submission.DestinationId, + new FitConnect.Models.AuthenticationTags() { + Data = _submission.AuthenticationTags.Data + "Invalid", + Metadata = _submission.AuthenticationTags.Metadata + "Invalid", + Attachments = _submission.AuthenticationTags.Attachments!.ToDictionary( + i => i.Key, + i => "InvalidTag!") + }); + + var exception = Assert.Throws<AggregateException>(() => + Sender.GetStatusForSubmissionAsync(manipulated).Wait()); + + exception.InnerExceptions.Any(e => e is AuthenticationTagException).Should().BeTrue(); + } } diff --git a/E2ETest/StraightPreEncryptedForwardTest.cs b/E2ETest/StraightPreEncryptedForwardTest.cs index 6a97d4919be74590f686f5f8c53c627b1bfd8b48..28f22f762e2e8d0803ef2fcbb319688493387d2a 100644 --- a/E2ETest/StraightPreEncryptedForwardTest.cs +++ b/E2ETest/StraightPreEncryptedForwardTest.cs @@ -1,6 +1,8 @@ +using System.Security.Authentication; using FitConnect; using FitConnect.Encryption; using FitConnect.Models; +using FitConnect.Models.v1.Api; using FluentAssertions; using Microsoft.Extensions.Logging; using Newtonsoft.Json; @@ -10,8 +12,7 @@ namespace E2ETest; [Order(30)] [TestFixture] public class StraightPreEncryptedForwardTest : EndToEndTestBase { - private string _caseId = null!; - private string _submissionId = null!; + private SentSubmission _submission = null!; [Order(10)] [Test] @@ -59,19 +60,21 @@ public class StraightPreEncryptedForwardTest : EndToEndTestBase { var result = Sender.SendAsync(submission).Result; - if (result.CaseId == null || result.CaseId == null) - throw new NullReferenceException( - $"Neither {nameof(result.CaseId)} nor {nameof(result.SubmissionId)} must not be null"); + // Assert + _submission = result; - _caseId = result.CaseId!; - _submissionId = result.SubmissionId!; + _submission.CaseId.Should().NotBeNullOrWhiteSpace(); + _submission.SubmissionId.Should().NotBeNullOrWhiteSpace(); + _submission.AuthenticationTags.Attachments!.All(item => + !(string.IsNullOrWhiteSpace(item.Key) || string.IsNullOrWhiteSpace(item.Value))) + .Should().BeTrue(); } [Test] [Order(20)] - public void Sender_GetSubmissionState() { + public void Sender_GetEventLogForSubmission() { // Act - var status = Sender.GetStatusForSubmissionAsync(_caseId, Settings.DestinationId).Result; + var status = Sender.GetEventLogAsync(_submission.CaseId, Settings.DestinationId).Result; // Assert status.Count.Should().BeGreaterThan(0); @@ -80,11 +83,19 @@ public class StraightPreEncryptedForwardTest : EndToEndTestBase { s => Logger.LogInformation("Status {When} {Event}", s.EventTime, s.EventType)); } + [Test] + [Order(21)] + public void Sender_GetStatusForSubmission() { + var (status, problems) = Sender.GetStatusForSubmissionAsync(_submission).Result; + status.Should().Be(EventType.Submit); + } + + [Test] [Order(30)] public void Subscriber_GetSubmissionState() { // Act - var status = Subscriber.GetStatusForSubmissionAsync(_caseId, Settings.DestinationId).Result; + var status = Subscriber.GetEventLogAsync(_submission.CaseId, Settings.DestinationId).Result; // Assert status.Count.Should().BeGreaterThan(0); @@ -95,7 +106,8 @@ public class StraightPreEncryptedForwardTest : EndToEndTestBase { [Test] [Order(40)] public void RequestSubmission() { - var subscriberWithSubmission = Subscriber.RequestSubmissionAsync(_submissionId).Result; + var subscriberWithSubmission = + Subscriber.RequestSubmissionAsync(_submission.SubmissionId).Result; var data = subscriberWithSubmission.GetDataString(); Logger.LogInformation("Data {Data}", data); @@ -106,18 +118,47 @@ public class StraightPreEncryptedForwardTest : EndToEndTestBase { var attachments = subscriberWithSubmission.GetAttachmentsAsync().Result; attachments.First().Filename.Should().Be("Test.pdf"); - subscriberWithSubmission.AcceptSubmissionAsync().Wait(); + subscriberWithSubmission + .AcceptSubmissionAsync(new Problems(Problems.ProblemTypeEnum.MissingSchema, + "Schema missing")).Wait(); } [Test] [Order(50)] public void Sender_GetSubmissionState_AfterAccepting() { // Act - var status = Sender.GetStatusForSubmissionAsync(_caseId, Settings.DestinationId).Result; + var status = Sender.GetEventLogAsync(_submission.CaseId, Settings.DestinationId).Result; // Assert status.Count.Should().BeGreaterThan(0); status.ForEach( s => Logger.LogInformation("Status {When} {Event}", s.EventTime, s.EventType)); + + var acceptanceMessage = status.Last(); + acceptanceMessage.EventType.Should().Be(EventType.Accept); + + acceptanceMessage.Events!.AcceptSubmissionEvent!.Problems.Should().NotBeEmpty(); + + acceptanceMessage.Events?.AcceptSubmissionEvent?.Problems! + .Any(p => p.Detail == "Schema missing").Should().BeTrue(); + } + + [Test] + [Order(51)] + public void Sender_GetStatusForSubmission_FailsOnManipulatedAuthenticationTags() { + var manipulated = new SentSubmission(_submission.SubmissionId, _submission.CaseId, + _submission.DestinationId, + new FitConnect.Models.AuthenticationTags() { + Data = _submission.AuthenticationTags.Data + "Invalid", + Metadata = _submission.AuthenticationTags.Metadata + "Invalid", + Attachments = _submission.AuthenticationTags.Attachments!.ToDictionary( + i => i.Key, + i => "InvalidTag!") + }); + + var exception = Assert.Throws<AggregateException>(() => + Sender.GetStatusForSubmissionAsync(manipulated).Wait()); + + exception!.InnerExceptions.Any(e=>e is AuthenticationTagException).Should().BeTrue(); } } diff --git a/EncryptionTests/EncryptionTests.csproj b/EncryptionTests/EncryptionTests.csproj index 698bfa2db59a60db4866262ad61b60712dc207ba..c8bdd34574e78b2270e12a92907c8a0d5de12505 100644 --- a/EncryptionTests/EncryptionTests.csproj +++ b/EncryptionTests/EncryptionTests.csproj @@ -10,18 +10,21 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="FluentAssertions" Version="6.7.0"/> - <PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0"/> - <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="6.0.0"/> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0"/> - <PackageReference Include="NUnit" Version="3.13.2"/> - <PackageReference Include="NUnit3TestAdapter" Version="4.0.0"/> - <PackageReference Include="coverlet.collector" Version="3.1.0"/> + <PackageReference Include="FluentAssertions" Version="6.8.0" /> + <PackageReference Include="Microsoft.Extensions.Logging" Version="7.0.0" /> + <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="7.0.0" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.1" /> + <PackageReference Include="NUnit" Version="3.13.3" /> + <PackageReference Include="NUnit3TestAdapter" Version="4.3.1" /> + <PackageReference Include="coverlet.collector" Version="3.2.0"> + <PrivateAssets>all</PrivateAssets> + <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> + </PackageReference> </ItemGroup> <ItemGroup> - <ProjectReference Include="..\FitConnect\FitConnect.csproj"/> - <ProjectReference Include="..\MockContainer\MockContainer.csproj"/> + <ProjectReference Include="..\FitConnect\FitConnect.csproj" /> + <ProjectReference Include="..\MockContainer\MockContainer.csproj" /> </ItemGroup> <ItemGroup> diff --git a/FitConnect/Encryption/FitEncryption.cs b/FitConnect/Encryption/FitEncryption.cs index c301d97cd76d1353bc60c4203ea5ee9d030e26f7..90d1a32f98bf83416a01c8e8c8255c8f17c55c2c 100644 --- a/FitConnect/Encryption/FitEncryption.cs +++ b/FitConnect/Encryption/FitEncryption.cs @@ -115,6 +115,7 @@ public class FitEncryption { public async Task<string> CreateAcceptSecurityEventToken(ISubmitted submission, + IEnumerable<Problems>? problems = null, dynamic? payload = null) { if (submission?.SubmissionId == null || submission?.CaseId == null || submission?.DestinationId == null) @@ -123,17 +124,17 @@ public class FitEncryption { return await CreateSecurityEventToken(submission.SubmissionId, submission.CaseId, submission.DestinationId, new Events { - AcceptSubmissionEvent = new AcceptSubmissionEvent(payload) + AcceptSubmissionEvent = new AcceptSubmissionEvent(payload, problems) }); } - public async Task<string> CreateAcceptSecurityEventToken(Submission submission) { + public async Task<string> CreateAcceptSecurityEventToken(Submission submission, IEnumerable<Problems>? problems) { var payload = GenerateAuthenticationTags(submission); return await CreateSecurityEventToken(submission.Id, submission.CaseId, submission.DestinationId, new Events { - AcceptSubmissionEvent = new AcceptSubmissionEvent(payload) + AcceptSubmissionEvent = new AcceptSubmissionEvent(payload, problems) }); } diff --git a/FitConnect/Encryption/JoseEncryptor.cs b/FitConnect/Encryption/JoseEncryptor.cs index 12503ae9bb5b185dbc402b2e95468ed33db52421..26a174723df1d7719add7d155b2c770142c5b153 100644 --- a/FitConnect/Encryption/JoseEncryptor.cs +++ b/FitConnect/Encryption/JoseEncryptor.cs @@ -65,15 +65,6 @@ public class JoseEncryptor : IEncryptor { } } - // public bool TokenValidator(string signature, string key) { - // Jose.Jwk jwk = Jwk.FromJson(key, new JsonMapper()); - // var token = Jose.JweToken.FromString(signature); - // Jose. - // - // - // - // } - private (string plainText, byte[] plainBytes, byte[] tag) Decrypt(Jwk key, string payload) { var result = JWE.Decrypt(payload, key, Algorithm, Encryption); diff --git a/FitConnect/FitConnect.csproj b/FitConnect/FitConnect.csproj index deac871ac68f5f662afe8e4dd026cc084ee7a746..54a8a43129da4080b2b284308b471fb48da5d6fc 100644 --- a/FitConnect/FitConnect.csproj +++ b/FitConnect/FitConnect.csproj @@ -6,7 +6,7 @@ <Nullable>enable</Nullable> <AssemblyVersion></AssemblyVersion> <FileVersion></FileVersion> - <PackageVersion>0.9.0-beta.2</PackageVersion> + <PackageVersion>0.9.1-beta.1</PackageVersion> <Title>FIT-Connect .NET SDK</Title> <Description>Library for sending and receiving submissions via FIT-Connect</Description> <Copyright>2022 FIT-Connect contributors</Copyright> @@ -22,18 +22,18 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Autofac" Version="6.4.0" /> + <PackageReference Include="Autofac" Version="6.5.0" /> <PackageReference Include="IdentityModel" Version="6.0.0" /> - <PackageReference Include="jose-jwt" Version="4.0.0" /> + <PackageReference Include="jose-jwt" Version="4.1.0" /> <PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" /> - <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.1" /> - <PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="6.22.0" /> - <PackageReference Include="Microsoft.IdentityModel.Tokens" Version="6.22.0" /> + <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.0" /> + <PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="6.25.1" /> + <PackageReference Include="Microsoft.IdentityModel.Tokens" Version="6.25.1" /> <PackageReference Include="MimeTypeMap.List" Version="2.1.0" /> - <PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> + <PackageReference Include="Newtonsoft.Json" Version="13.0.2" /> <PackageReference Include="Newtonsoft.Json.Schema" Version="3.0.14" /> - <PackageReference Include="NJsonSchema" Version="10.7.2" /> - <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.21.0" /> + <PackageReference Include="NJsonSchema" Version="10.8.0" /> + <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.25.1" /> </ItemGroup> <ItemGroup> diff --git a/FitConnect/FitConnectClient.cs b/FitConnect/FitConnectClient.cs index adb2c8055ade6d4f8cf5093a648437499c0c8287..6596703ef579a1cf52936b0b77ed9acd53cffa64 100644 --- a/FitConnect/FitConnectClient.cs +++ b/FitConnect/FitConnectClient.cs @@ -1,7 +1,9 @@ using System.Net; +using System.Security.Authentication; using Autofac; using FitConnect.Encryption; using FitConnect.Models; +using FitConnect.Models.v1.Api; using FitConnect.Services; using FitConnect.Services.Interfaces; using FitConnect.Services.Models.v1.Submission; @@ -9,6 +11,7 @@ using Microsoft.Extensions.Logging; using Microsoft.IdentityModel.Tokens; using NJsonSchema; using NJsonSchema.Validation; +using SecurityEventToken = FitConnect.Models.SecurityEventToken; namespace FitConnect; @@ -118,11 +121,11 @@ public abstract class FitConnectClient { /// <param name="destinationId"></param> /// <param name="skipTest"></param> /// <returns></returns> - public async Task<List<SecurityEventToken>> GetStatusForSubmissionAsync(string caseId, + public async Task<List<SecurityEventToken>> GetEventLogAsync(string caseId, string destinationId, bool skipTest = false) { var events = - (await SubmissionService.GetStatusForSubmissionAsync(caseId, destinationId, skipTest)) + (await SubmissionService.GetEventLogAsync(caseId, destinationId, skipTest)) ?.Select(SecurityEventToken.FromJwtEncodedString).ToList() ?? new List<SecurityEventToken>(); return events; @@ -134,18 +137,45 @@ public abstract class FitConnectClient { /// <param name="submission"></param> /// <param name="skipTest"></param> /// <returns></returns> - public async Task<List<SecurityEventToken>> GetStatusForSubmissionAsync( + public async Task<List<SecurityEventToken>> GetEventLogAsync( SubmissionForPickupDto submission, bool skipTest = false) { if (submission?.CaseId == null || submission.DestinationId == null) throw new ArgumentNullException(nameof(submission)); var events = await SubmissionService - .GetStatusForSubmissionAsync(submission.CaseId, submission.DestinationId, skipTest); + .GetEventLogAsync(submission.CaseId, submission.DestinationId, skipTest); return events?.Select(SecurityEventToken.FromJwtEncodedString).ToList() ?? new List<SecurityEventToken>(); } + /// <summary> + /// + /// </summary> + /// <param name="submission"></param> + /// <returns></returns> + public async Task<SubmissionState> GetStatusForSubmissionAsync( + SentSubmission submission) { + var eventLog = await GetEventLogAsync(submission.CaseId, submission.DestinationId); + + var status = eventLog.Last(e => e.SubmissionId == submission.SubmissionId); + List<Problems>? problems = null; + + if (status.Events?.AcceptSubmissionEvent != null) { + if (!(status.Events.AcceptSubmissionEvent.AuthenticationTags ?? + throw new InvalidOperationException()).AreEqualTo(submission + .AuthenticationTags)) { + throw new AuthenticationTagException("Authentication tags are not equal"); + } + + problems = status.Events.AcceptSubmissionEvent.Problems; + } + else if (status.Events?.RejectSubmissionEvent != null) + problems = status.Events.RejectSubmissionEvent.Problems; + + return new SubmissionState(status.EventType, problems); + } + /// <summary> /// Encrypt attachments (Anhänge) /// </summary> diff --git a/FitConnect/Interfaces/IFitConnectClient.cs b/FitConnect/Interfaces/IFitConnectClient.cs index b6d95f2c5ae9074d4ce6d05765f977fc38aa6cd1..7377ca9e1cedf3dfd23eb8e7c642d31bb1589cc3 100644 --- a/FitConnect/Interfaces/IFitConnectClient.cs +++ b/FitConnect/Interfaces/IFitConnectClient.cs @@ -11,7 +11,7 @@ public interface IFitConnectClient { /// <param name="destinationId">Skips signature validation if null!</param> /// <param name="skipTest">Specifies if the SET signature test is skipped</param> /// <returns>List of the <see cref="SecurityEventToken" /></returns> - public Task<List<SecurityEventToken>> GetStatusForSubmissionAsync(string caseId, + public Task<List<SecurityEventToken>> GetEventLogAsync(string caseId, string destinationId, bool skipTest = false); } diff --git a/FitConnect/Interfaces/ISender.cs b/FitConnect/Interfaces/ISender.cs index b82825555277f3df386e3976160db017f7f96e20..aa5f1ef45e99f327638deaac68a73c6a43b14945 100644 --- a/FitConnect/Interfaces/ISender.cs +++ b/FitConnect/Interfaces/ISender.cs @@ -1,4 +1,5 @@ using FitConnect.Models; +using FitConnect.Models.v1.Api; using Route = FitConnect.Services.Models.v1.Routes.Route; namespace FitConnect.Interfaces; @@ -25,7 +26,7 @@ public interface ISender : IFitConnectClient { /// the submission /// </param> /// <returns></returns> - Task<Submission> SendAsync(SendableSubmission submission); + Task<SentSubmission> SendAsync(SendableSubmission submission); /// <summary> /// Sending a pre-encrypted submission @@ -35,7 +36,7 @@ public interface ISender : IFitConnectClient { /// to create the submission /// </param> /// <returns></returns> - Task<Submitted> SendAsync(SendableEncryptedSubmission submission); + Task<SentSubmission> SendAsync(SendableEncryptedSubmission submission); /// <summary> /// Receives the public key for the destination with the id <paramref name="destinationId" /> @@ -43,4 +44,10 @@ public interface ISender : IFitConnectClient { /// <param name="destinationId">Destination id of the requested public key</param> /// <returns></returns> Task<string> GetPublicKeyForDestinationAsync(string destinationId); + + /// <summary> + /// Requesting the state of the submission + /// </summary> + /// <returns></returns> + Task<SubmissionState> GetStatusForSubmissionAsync(SentSubmission submission); } diff --git a/FitConnect/Interfaces/Subscriber/ISubscriber.cs b/FitConnect/Interfaces/Subscriber/ISubscriber.cs index f3c92c5ae30882a91fec5a611706fede2dddb075..83f42b19a048fa749d1b43e5878f903a14b5d9fd 100644 --- a/FitConnect/Interfaces/Subscriber/ISubscriber.cs +++ b/FitConnect/Interfaces/Subscriber/ISubscriber.cs @@ -20,10 +20,16 @@ public interface ISubscriber : IFitConnectClient { /// Loads a single Submission by id. /// </summary> /// <param name="submissionId">unique identifier of a <see cref="Submission" /></param> - /// <param name="skipSchemaTest"></param> /// <returns>A subscriber object with a submission</returns> public Task<ISubscriberWithSubmission> RequestSubmissionAsync(string submissionId); + /// <summary> + /// Loads a single Submission. + /// </summary> + /// <param name="submission"></param> + /// <returns>A subscriber object with a submission</returns> + public Task<ISubscriberWithSubmission> RequestSubmissionAsync(SubmissionForPickupDto submission); + /// <summary> /// Rejecting a submission /// </summary> diff --git a/FitConnect/Interfaces/Subscriber/ISubscriberWithSubmission.cs b/FitConnect/Interfaces/Subscriber/ISubscriberWithSubmission.cs index 09a0b47d50800f22a8a2499121d7eae6eaee21a0..eca2ff16e14c406d1e45aea0dc8eb3df9797bd3f 100644 --- a/FitConnect/Interfaces/Subscriber/ISubscriberWithSubmission.cs +++ b/FitConnect/Interfaces/Subscriber/ISubscriberWithSubmission.cs @@ -24,7 +24,7 @@ public interface ISubscriberWithSubmission : WithSubmission { /// <summary> /// Accept submission and delete it from the server /// </summary> - public Task AcceptSubmissionAsync(); + public Task AcceptSubmissionAsync(params Problems[] problems); /// <summary> /// Rejects the submission diff --git a/FitConnect/Models/Attachment.cs b/FitConnect/Models/Attachment.cs index 22360bfbbf0225c95447f2c153b738f8a7cf5f52..7c18f24fd27f4691b785162d130fc64c289b593a 100644 --- a/FitConnect/Models/Attachment.cs +++ b/FitConnect/Models/Attachment.cs @@ -17,19 +17,15 @@ public class Attachment { : metadata.MimeType; } - - /// <summary> - /// Attachment for a submission. - /// </summary> - /// <param name="filename">File name to load</param> - /// <param name="description">Description of the attachment</param> + /// <summary> /// Attachment for a submission. /// </summary> /// <param name="filename">File name to load</param> /// <param name="description">Description of the attachment</param> - public Attachment(string filename, string description, string? mimeType = null) { - Content = File.ReadAllBytes(filename); + public Attachment(string filename, string description, string? mimeType = null, + byte[]? buffer = null) { + Content = buffer ?? File.ReadAllBytes(filename); Filename = Path.GetFileName(filename); MimeType = mimeType ?? MimeTypeMap.List.MimeTypeMap.GetMimeType(Path.GetExtension(filename)) .First(); @@ -45,7 +41,7 @@ public class Attachment { public string Id { get; } = Guid.NewGuid().ToString(); public byte[]? Content { get; init; } - public string? AttachmentAuthentication { get; } + public string? AttachmentAuthentication { get; internal set; } public string? Hash => CalculateHash(); diff --git a/FitConnect/Models/EncryptedSubmission.cs b/FitConnect/Models/EncryptedSubmission.cs new file mode 100644 index 0000000000000000000000000000000000000000..cc7c4bf7f875431dfb92b08370654432d8b51aa8 --- /dev/null +++ b/FitConnect/Models/EncryptedSubmission.cs @@ -0,0 +1,43 @@ +using Newtonsoft.Json; + +namespace FitConnect.Models; + +public class EncryptedSubmission { + public EncryptedSubmission(string destinationId, string serviceName, string leikaKey, + string data, string metadata, Dictionary<string, string> attachments) { + DestinationId = destinationId; + ServiceName = serviceName; + LeikaKey = leikaKey; + Data = data; + Metadata = metadata; + Attachments = attachments; + } + + [JsonProperty("destinationId")] + public string DestinationId { get; init; } + + [JsonProperty("serviceName")] + public string ServiceName { get; init; } + + [JsonProperty("leikaKey")] + public string LeikaKey { get; init; } + + [JsonProperty("data")] + public string Data { get; init; } + + [JsonProperty("metadata")] + public string Metadata { get; init; } + + [JsonProperty("attachments")] + public Dictionary<string, string> Attachments { get; init; } + + public void Deconstruct(out string destinationId, out string serviceName, out string leikaKey, + out string data, out string metadata, out Dictionary<string, string> attachments) { + destinationId = DestinationId; + serviceName = ServiceName; + leikaKey = LeikaKey; + data = Data; + metadata = Metadata; + attachments = Attachments; + } +} diff --git a/FitConnect/Models/FitConnectException.cs b/FitConnect/Models/FitConnectException.cs index 91ca6c592ae3525804d42abe2e2e3a576ab3173a..d1fdf759d9b3380df5b560677a7f6c4e32643e33 100644 --- a/FitConnect/Models/FitConnectException.cs +++ b/FitConnect/Models/FitConnectException.cs @@ -15,3 +15,9 @@ public class FitConnectException : Exception { public ErrorTypeEnum ErrorType { get; set; } } + +public class AuthenticationTagException : Exception { + public AuthenticationTagException(string message, + Exception? innerException = null) : base(message, innerException) { + } +} diff --git a/FitConnect/Models/SET/AcceptSubmissionEvent.cs b/FitConnect/Models/SET/AcceptSubmissionEvent.cs index 0660a7f801887e5fdfb0835e868252646d1ed14d..36d405a63601af681024bf603f853a1d5cda0dcd 100644 --- a/FitConnect/Models/SET/AcceptSubmissionEvent.cs +++ b/FitConnect/Models/SET/AcceptSubmissionEvent.cs @@ -3,14 +3,20 @@ using Newtonsoft.Json; namespace FitConnect.Models; -public class AcceptSubmissionEvent : SubmitSubmissionEvent, ISubmissionEvent { +public class AcceptSubmissionEvent : SubmitSubmissionEvent, ISubmissionEvent, IStatusWithProblems { public AcceptSubmissionEvent() { } - public AcceptSubmissionEvent(AuthenticationTags payload) { + + public AcceptSubmissionEvent(AuthenticationTags payload, IEnumerable<Problems>? problems) { this.AuthenticationTags = payload; + this.Problems = problems?.ToList(); } [JsonProperty("problems", NullValueHandling = NullValueHandling.Ignore)] public List<Problems>? Problems { get; set; } -} \ No newline at end of file +} + +public interface IStatusWithProblems { + public List<Problems>? Problems { get; set; } +} diff --git a/FitConnect/Models/SET/AuthenticationTags.cs b/FitConnect/Models/SET/AuthenticationTags.cs index 18382365f11800510c9b487b429f85c4d87b1d12..13c12f5c7036eb24f3f63b1ad8fc797524a84c58 100644 --- a/FitConnect/Models/SET/AuthenticationTags.cs +++ b/FitConnect/Models/SET/AuthenticationTags.cs @@ -1,3 +1,4 @@ +using FitConnect.Models.v1.Api; using Newtonsoft.Json; namespace FitConnect.Models; @@ -11,4 +12,22 @@ public class AuthenticationTags { [JsonProperty("attachments", NullValueHandling = NullValueHandling.Ignore)] public Dictionary<string, string>? Attachments { get; set; } -} \ No newline at end of file +} + +public static class AuthenticationTagExtensions { + public static bool AreEqualTo(this AuthenticationTags expected, AuthenticationTags actual) { + if (expected.Attachments == null && actual.Attachments == null) { + return expected.Data == actual.Data && expected.Metadata == actual.Metadata; + } + + if (actual.Attachments == null ^ expected.Attachments == null) { + return false; + } + + return expected.Metadata == actual.Metadata + && expected.Data == actual.Data + && expected.Attachments!.Any((item) => + actual.Attachments!.ContainsKey(item.Key) && + actual.Attachments[item.Key] == item.Value); + } +} diff --git a/FitConnect/Models/SET/RejectSubmissionEvent.cs b/FitConnect/Models/SET/RejectSubmissionEvent.cs index 8338e74a41f803ebb8aeba63219d1798cf6c3195..ec61294f98e972f18662d743a3bad9511aa84678 100644 --- a/FitConnect/Models/SET/RejectSubmissionEvent.cs +++ b/FitConnect/Models/SET/RejectSubmissionEvent.cs @@ -3,15 +3,15 @@ using Newtonsoft.Json; namespace FitConnect.Models; -public class RejectSubmissionEvent : ISubmissionEvent { +public class RejectSubmissionEvent : ISubmissionEvent, IStatusWithProblems { public RejectSubmissionEvent() { Problems = new List<Problems>(); } - public RejectSubmissionEvent(Problems[] problemsArray) { + public RejectSubmissionEvent(IEnumerable<Problems> problemsArray) { this.Problems = problemsArray.ToList(); } [JsonProperty("problems", NullValueHandling = NullValueHandling.Ignore)] - public List<Problems> Problems { get; set; } + public List<Problems>? Problems { get; set; } } \ No newline at end of file diff --git a/FitConnect/Models/SET/SubmissionState.cs b/FitConnect/Models/SET/SubmissionState.cs new file mode 100644 index 0000000000000000000000000000000000000000..cff517930ad913e25fc6d5551a286c45a232d190 --- /dev/null +++ b/FitConnect/Models/SET/SubmissionState.cs @@ -0,0 +1,21 @@ +using FitConnect.Models.v1.Api; + +namespace FitConnect.Models; + +/// <summary> +/// The current status of the submission. +/// </summary> +public class SubmissionState { + public SubmissionState(EventType statusEventType, List<Problems>? problems) { + Status = statusEventType; + Problems = problems; + } + + public EventType Status { get; } + public List<Problems>? Problems { get; } + + public void Deconstruct(out EventType status, out List<Problems>? problems) { + status = Status; + problems = Problems; + } +} diff --git a/FitConnect/Models/Submission.cs b/FitConnect/Models/Submission.cs index eb417c097181ef5a90bd72f0773cf32a2d87780c..e5df47f05bc084052b2c946d1ee30ab173bd3fd4 100644 --- a/FitConnect/Models/Submission.cs +++ b/FitConnect/Models/Submission.cs @@ -110,6 +110,35 @@ public interface ISubmitted { public string? DestinationId { get; } } +public class SentSubmission : ISubmitted { + public SentSubmission(string submissionId, string caseId, string destinationId, + AuthenticationTags authenticationTags) { + SubmissionId = submissionId; + CaseId = caseId; + DestinationId = destinationId; + AuthenticationTags = authenticationTags; + } + + public string SubmissionId { get; set; } + public string CaseId { get; set; } + public string DestinationId { get; set; } + public AuthenticationTags AuthenticationTags { get; set; } + + + public static explicit operator SentSubmission(Submission submission) + => new SentSubmission( + submission.Id, + submission.CaseId, + submission.DestinationId, + new AuthenticationTags { + Data = submission.DataAuthentication, + Metadata = submission.MetaAuthentication, + Attachments = + submission.Attachments?.ToDictionary(i => i.Id, + i => i.AttachmentAuthentication!) + }); +} + public class Submitted : ISubmitted { public Submitted() { } diff --git a/FitConnect/Sender.cs b/FitConnect/Sender.cs index e16aacee206ec77392caaafe179804a63c8a2870..3fb61b07b871915345c42a6d5e1bbf0794e6dab4 100644 --- a/FitConnect/Sender.cs +++ b/FitConnect/Sender.cs @@ -54,7 +54,7 @@ public class Sender : FitConnectClient, ISender { return publicKey; } - public async Task<Submission> SendAsync(SendableSubmission submission) { + public async Task<SentSubmission> SendAsync(SendableSubmission submission) { var sendable = await CreateSubmission(submission.DestinationId); sendable.AddServiceType(submission.ServiceName!, submission.LeikaKey!); @@ -75,7 +75,12 @@ public class Sender : FitConnectClient, ISender { var encryptedAttachments = Encrypt(PublicKey!, sendable.Attachments); await UploadAttachmentsAsync(sendable.Id!, encryptedAttachments); - return await Submit(sendable); + foreach (var (key, value) in encryptedAttachments) { + var item = submission.Attachments!.Single(i => i.Id == key); + item.AttachmentAuthentication = value.Split('.').Last(); + } + + return (SentSubmission)await Submit(sendable); } @@ -86,7 +91,7 @@ public class Sender : FitConnectClient, ISender { /// <returns></returns> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="ArgumentException"></exception> - public async Task<Submitted> SendAsync(SendableEncryptedSubmission submission) { + public async Task<SentSubmission> SendAsync(SendableEncryptedSubmission submission) { SubmissionSenderGuards(submission); var sendable = await CreateSubmission(submission.DestinationId); @@ -109,7 +114,7 @@ public class Sender : FitConnectClient, ISender { Logger?.LogInformation("Uploading pre encrypted attachments"); await UploadAttachmentsAsync(sendable.Id!, submission.Attachments!); - return await Submit(sendable); + return (SentSubmission)(await Submit(sendable)); } diff --git a/FitConnect/Services/Interfaces/ISubmissionService.cs b/FitConnect/Services/Interfaces/ISubmissionService.cs index 6bbbd1047085b6763202103d17f5cd6eb59bbe27..78a015c4efcab4ec138c85231e3956d79bf04e0f 100644 --- a/FitConnect/Services/Interfaces/ISubmissionService.cs +++ b/FitConnect/Services/Interfaces/ISubmissionService.cs @@ -85,7 +85,7 @@ public interface ISubmissionService : IRestCallService { /// <param name="destinationId"></param> /// <param name="skipTest"></param> /// <returns></returns> - Task<List<string>?> GetStatusForSubmissionAsync(string caseId, string destinationId, + Task<List<string>?> GetEventLogAsync(string caseId, string destinationId, bool skipTest = false); } diff --git a/FitConnect/Services/SubmissionService.cs b/FitConnect/Services/SubmissionService.cs index 7c24344ced1957acab8253b2f38551b4692fc92d..9dca6567170fca313964763c16661f9af016e6ca 100644 --- a/FitConnect/Services/SubmissionService.cs +++ b/FitConnect/Services/SubmissionService.cs @@ -145,7 +145,7 @@ internal class SubmissionService : RestCallService, ISubmissionService { throw new NotImplementedException(); } - public async Task<List<string>?> GetStatusForSubmissionAsync(string caseId, + public async Task<List<string>?> GetEventLogAsync(string caseId, string destinationId, bool skipTest = false) { await _oAuthService.EnsureAuthenticatedAsync(); diff --git a/FitConnect/SubmissionBuilder.cs b/FitConnect/SubmissionBuilder.cs index 4fedb82be8dcc9326017c4e6cc9c546fe486db35..ca0d6b974c1cde74ea424f2e243203cd461a0535 100644 --- a/FitConnect/SubmissionBuilder.cs +++ b/FitConnect/SubmissionBuilder.cs @@ -19,8 +19,27 @@ public class SubmissionBuilder : ISubmissionWithDestination, return WithAttachments(attachments.ToArray()); } + private ISubmissionWithData WithAttachments(string fileName, string description, string mimeType, + FileStream fileStream) { + byte[]? buffer; + using (fileStream) { + buffer = new byte[fileStream.Length]; + fileStream.Read(buffer, 0, (int)fileStream.Length); + } + + var attachment = new Attachment(fileName, description, mimeType, buffer); + + return WithAttachments(attachment); + } + public ISubmissionWithData WithAttachments(params Attachment[] attachments) { - _submissionToSend.Attachments = attachments; + _submissionToSend.Attachments ??= new Attachment[] { }; + + foreach (var attachment in attachments) { + _submissionToSend.Attachments = + _submissionToSend.Attachments.Append(attachment).ToArray(); + } + return this; } @@ -89,6 +108,13 @@ public interface ISubmissionWithData { ISubmissionWithData WithAttachments(params Attachment[] attachments); ISubmissionWithData WithAttachments(List<Attachment> attachments); + /// <summary> + /// For future use + /// </summary> + /// <returns></returns> + // ISubmissionWithData WithAttachments(string fileName, string description, string mimeType, + // FileStream content); + SendableSubmission Build(); } diff --git a/FitConnect/Subscriber.cs b/FitConnect/Subscriber.cs index 4248ed2fa8082394214080ed08ece4a99924635c..7bb4ee1b506ccf892cb28da7e17b8a35e2306ff9 100644 --- a/FitConnect/Subscriber.cs +++ b/FitConnect/Subscriber.cs @@ -68,6 +68,10 @@ public class Subscriber : FitConnectClient, ISubscriberWithSubmission, } + public async Task<ISubscriberWithSubmission> + RequestSubmissionAsync(SubmissionForPickupDto submission) => + await RequestSubmissionAsync(submission.Id); + /// <summary> /// Receives a specific submission from the server and verifies submission<br /> /// https://docs.fitko.de/fit-connect/docs/receiving/verification/ @@ -119,24 +123,25 @@ public class Subscriber : FitConnectClient, ISubscriberWithSubmission, Problems.TitleMissingSchema, Problems.DetailMissingSchema, Problems.ProblemInstanceEnum.Metadata); - await RejectSubmissionAsync(submission, problem); - throw new SecurityEventException(problem); + // await RejectSubmissionAsync(submission, problem); + // throw new SecurityEventException(problem); } + else { + JsonSchema? schema; + try { + schema = await JsonSchema.FromUrlAsync(submission.Metadata?.Schema); + } + catch (Exception e) { + // SuccessCriteria:3.5 + var problem = new Problems(Problems.ProblemTypeEnum.UnsupportedMetaSchema, + Problems.DetailUnsupportedSchema); + await RejectSubmissionAsync(submission, problem); + throw new SecurityEventException(problem, e); + } - JsonSchema? schema; - try { - schema = await JsonSchema.FromUrlAsync(submission.Metadata?.Schema); - } - catch (Exception e) { - // SuccessCriteria:3.5 - var problem = new Problems(Problems.ProblemTypeEnum.UnsupportedMetaSchema, - Problems.DetailUnsupportedSchema); - await RejectSubmissionAsync(submission, problem); - throw new SecurityEventException(problem, e); + await VerifyMetadata(submission, metadataString, schema); } - await VerifyMetadata(submission, metadataString, schema); - // SuccessCriteria:3.3 if (submission.Metadata == null) { var problem = new Problems(Problems.ProblemTypeEnum.SyntaxViolation, @@ -295,8 +300,8 @@ public class Subscriber : FitConnectClient, ISubscriberWithSubmission, return attachments; } - public async Task AcceptSubmissionAsync() { - await CompleteSubmissionAsync(Submission!, FinishSubmissionStatus.Accepted); + public async Task AcceptSubmissionAsync(params Problems[] problems) { + await CompleteSubmissionAsync(Submission!, FinishSubmissionStatus.Accepted, problems); } public async Task RejectSubmissionAsync(params Problems[] problems) { @@ -372,6 +377,10 @@ public class Subscriber : FitConnectClient, ISubscriberWithSubmission, // SuccessCriteria: Hash-Check 5.4 if (attachmentMeta?.Hash.Content != FitEncryption.CalculateHash(content).Content) { + Logger?.LogWarning( + "Wrong hash for attachment {attachment}\nHash should be {should} but is {is}", + id, FitEncryption.CalculateHash(content).Content, + attachmentMeta?.Hash.Content); var problem = new Problems( Problems.ProblemTypeEnum.HashMismatch, Problems.TitleHashMismatch, @@ -429,11 +438,6 @@ public class Subscriber : FitConnectClient, ISubscriberWithSubmission, submission.DestinationId == null) throw new ArgumentException("Submission does not contain all required fields"); - if (status != FinishSubmissionStatus.Rejected && problems != null) - throw new ArgumentException("Problems can only be set for rejected submissions"); - - // TODO Generate AuthenticationTags for Accept token - string? token; switch (status) { case FinishSubmissionStatus.Rejected: @@ -445,7 +449,7 @@ public class Subscriber : FitConnectClient, ISubscriberWithSubmission, if (submission is Submission sub) { var authenticationTags = FitEncryption.GenerateAuthenticationTags(sub); - token = await Encryption.CreateAcceptSecurityEventToken(submission, + token = await Encryption.CreateAcceptSecurityEventToken(submission, problems, authenticationTags); } else { @@ -589,7 +593,7 @@ public class Subscriber : FitConnectClient, ISubscriberWithSubmission, Submission submission) { List<SecurityEventToken> status; try { - status = await GetStatusForSubmissionAsync(submission); + status = await GetEventLogAsync(submission); } catch (Exception? e) { Logger?.LogWarning("Could not get status for submission: {SubmissionId}", diff --git a/FitConnect/nuget-readme.md b/FitConnect/nuget-readme.md index 5391dda7f7cfce0bd5d12eaf2794741406c29a02..198ed5d498554d6982a5fd0a6aae10debdd3684e 100644 --- a/FitConnect/nuget-readme.md +++ b/FitConnect/nuget-readme.md @@ -12,7 +12,7 @@ Auf OSX wird das SDK nur dann unterstützt, wenn OpenSSL auf dem System installi Zum Installieren von OpenSSL können Sie Homebrew verwenden: ```sh -brew install openssl@1.1 +brew install openssl ``` Die Environment-Variable ```DYLD_LIBRARY_PATH``` muss auf den Pfad zu OpenSSL verweisen. @@ -21,7 +21,7 @@ _Beispiele:_ ```sh export DYLD_LIBRARY_PATH=/usr/local/opt/openssl/lib -export DYLD_LIBRARY_PATH=/usr/local/opt/openssl@1.1/lib +export DYLD_LIBRARY_PATH=/opt/homebrew/opt/openssl@3/lib ``` ### Sender @@ -46,6 +46,15 @@ In der Produktivumgebung müssen hierzu [Zertifikate der Verwaltungs-PKI zum Ein ## Sender +### Instanz des Senders erzeugen + +Der `Sender` wir in einem *Builder* im `Client` erstellt. +Dazu werden die `FitConnectEnvironment`, die _ClientId_ und das _ClientSecret_ benötigt. + +```csharp +var sender = Client.GetSender(FitConnectEnvironment.Testing, clientId, clientSecret, logger); +``` + ### Erstellen einer Einreichung (submission) Das folgende Beispiel zeigt, wie Sie das SDK in einem sendenden System nutzen, um eine Submission (eine Einreichung) zu erzeugen und zu senden: @@ -58,13 +67,31 @@ var submission = SubmissionBuilder .WithData("{\"message\":\"Hello World\"}") .Build(); -await Client.GetSender(FitConnectEnvironment.Testing, clientId, clientSecret, logger).SendAsync(submission); +await sender.SendAsync(submission); ``` Im Beispiel oben stellt das Argument "FitConnectEnvironment.Testing" die FIT-Connect-Endpunkte zur Verfügung, die aufgerufen werden sollen. Das Argument 'destinationId" enthält die eindeutige Adresse des empfangenden Systems (Fachverfahrens), das die Antragsdaten über FIT-Connect erhalten soll. Das Argument "leikaKey" stellt die ID der beantragten Leistung bereit. "Leika" ist die Abkürzung für "Leistungskatalog". +### Abrufen des Event-Logs und des Status' + +Der `sender` verfügt über eine Methode `GetEventLogAsync()` und `GetStatusForSubmissionAsync()` mit denen der aktuelle Status der Submission beim Zustelldienst abgefragt werden kann. + +```csharp +var (status, problems) = await sender.GetStatusForSubmission(sentSubmission); +``` + +Die SentSubmission enthält alle nottwendigen Informationen, um den Status abzufragen. +Auch die `AthenticationTags` sind darin enthalten mit denen der Status überprüft werden kann. + +Der `status` beinhaltet den aktuellen _Zustand_ der Submission. +In den `problems` sind Rückmeldungen vom _Subscriber_ enthalten. + +Das gesamte `EventLog` kann ebenfalls abgerufen werden. +Dazu wird die Methode `sender.GetEventLogAsync(caseId, destinationId)` aufgerufen. +Eine Überprüfung der Gültikeit des Statuses erfolgt hier **nicht**. + ## Subscriber ### Erstellen eines Subscribers diff --git a/IntegrationTests/IntegrationTests.csproj b/IntegrationTests/IntegrationTests.csproj index e98fdfa30328e02eb43801fe8e63c95690ee343c..582d796fd27062dabdc60c6a4e83fcb2873ce7d7 100644 --- a/IntegrationTests/IntegrationTests.csproj +++ b/IntegrationTests/IntegrationTests.csproj @@ -8,22 +8,25 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="DotNet.Testcontainers" Version="1.6.0"/> - <PackageReference Include="FluentAssertions" Version="6.7.0"/> - <PackageReference Include="Microsoft.AspNetCore.Http" Version="2.2.2"/> - <PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0"/> - <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="6.0.0"/> - <PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="6.22.0"/> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0"/> - <PackageReference Include="Newtonsoft.Json.Schema" Version="3.0.14"/> - <PackageReference Include="NUnit" Version="3.13.2"/> - <PackageReference Include="NUnit3TestAdapter" Version="4.0.0"/> - <PackageReference Include="coverlet.collector" Version="3.1.0"/> + <PackageReference Include="DotNet.Testcontainers" Version="1.6.0" /> + <PackageReference Include="FluentAssertions" Version="6.8.0" /> + <PackageReference Include="Microsoft.AspNetCore.Http" Version="2.2.2" /> + <PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" /> + <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="7.0.0" /> + <PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="6.25.1" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.1" /> + <PackageReference Include="Newtonsoft.Json.Schema" Version="3.0.14" /> + <PackageReference Include="NUnit" Version="3.13.3" /> + <PackageReference Include="NUnit3TestAdapter" Version="4.3.1" /> + <PackageReference Include="coverlet.collector" Version="3.2.0"> + <PrivateAssets>all</PrivateAssets> + <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> + </PackageReference> </ItemGroup> <ItemGroup> - <ProjectReference Include="..\FitConnect\FitConnect.csproj"/> - <ProjectReference Include="..\MockContainer\MockContainer.csproj"/> + <ProjectReference Include="..\FitConnect\FitConnect.csproj" /> + <ProjectReference Include="..\MockContainer\MockContainer.csproj" /> </ItemGroup> <ItemGroup> diff --git a/IntegrationTests/Sender/SenderTestHappyPath.cs b/IntegrationTests/Sender/SenderTestHappyPath.cs index 4ce8d67fbc0b3f19cc995d05d3d062b82fb611f5..12f030972c24d27059428829f10bd74083944f28 100644 --- a/IntegrationTests/Sender/SenderTestHappyPath.cs +++ b/IntegrationTests/Sender/SenderTestHappyPath.cs @@ -23,7 +23,7 @@ public class SenderTestHappyPath : SenderTestBase { [TestCase("d2be2027-9368-4c0c-a265-2fdbf7ecd4d9")] public void GetSubmissionStatus(string caseId) { var status = - Sender.GetStatusForSubmissionAsync(caseId, "aa3704d6-8bd7-4d40-a8af-501851f93934", true) + Sender.GetEventLogAsync(caseId, "aa3704d6-8bd7-4d40-a8af-501851f93934", true) .Result; status.ForEach(s => Console.WriteLine($"{s.EventTime} - {s.EventType}")); status.Count.Should().BeGreaterThan(0); @@ -83,12 +83,12 @@ public class SenderTestHappyPath : SenderTestBase { // Assert var statusForSubmission = - Sender.GetStatusForSubmissionAsync(submission.CaseId, DestinationId).Result; + Sender.GetEventLogAsync(submission.CaseId, DestinationId).Result; statusForSubmission.Should().HaveCountGreaterThan(0); Console.WriteLine($"Case ID: {submission.CaseId}"); - Console.WriteLine($"Submission ID: {submission.Id}"); + Console.WriteLine($"Submission ID: {submission.SubmissionId}"); submission.Should().NotBeNull(); } @@ -127,11 +127,11 @@ public class SenderTestHappyPath : SenderTestBase { // Assert var statusForSubmission = - Sender.GetStatusForSubmissionAsync(submission.Id, DestinationId).Result; + Sender.GetEventLogAsync(submission.SubmissionId, DestinationId).Result; statusForSubmission.Should().HaveCountGreaterThan(0); Console.WriteLine($"Case ID: {submission.CaseId}"); - Console.WriteLine($"Submission ID: {submission.Id}"); + Console.WriteLine($"Submission ID: {submission.SubmissionId}"); submission.Should().NotBeNull(); } diff --git a/IntegrationTests/Subscriber/SubscriberTestHappyPath.cs b/IntegrationTests/Subscriber/SubscriberTestHappyPath.cs index 90458d5a4e00ead02c4741ec57d7a67371559e8c..286826e8ecce0866449434a7fbccee38dab7ce2a 100644 --- a/IntegrationTests/Subscriber/SubscriberTestHappyPath.cs +++ b/IntegrationTests/Subscriber/SubscriberTestHappyPath.cs @@ -78,7 +78,7 @@ public class SubscriberTestHappyPath : SubscriberTestBase { submissions.Count().Should().BeGreaterThan(0); foreach (var submission in submissions) - Subscriber.GetStatusForSubmissionAsync(submission.CaseId!, DestinationId).Result + Subscriber.GetEventLogAsync(submission.CaseId!, DestinationId).Result .ForEach(s => Logger.LogInformation("{SubmissionCaseId} - {ObjEventTime} - {ObjEventType}", submission.CaseId, s.EventTime, s.EventType)); @@ -99,7 +99,7 @@ public class SubscriberTestHappyPath : SubscriberTestBase { if (!Directory.Exists($"./attachments/{submissionId}/")) Directory.CreateDirectory($"./attachments/{submissionId}/"); - Subscriber.GetStatusForSubmissionAsync(submission.CaseId!, DestinationId).Result + Subscriber.GetEventLogAsync(submission.CaseId!, DestinationId).Result .ForEach(s => Console.WriteLine($"{s.EventTime} - {s.EventType}")); diff --git a/MockContainer/MockContainer.csproj b/MockContainer/MockContainer.csproj index 11e75c39d7f925887db00eb4dc4e413eb83f4805..6ba4b2bd062c8de222e6886b1a34fd732cc012d5 100644 --- a/MockContainer/MockContainer.csproj +++ b/MockContainer/MockContainer.csproj @@ -8,14 +8,14 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Autofac" Version="6.4.0"/> - <PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0"/> - <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="6.0.0"/> - <PackageReference Include="Moq" Version="4.18.1"/> + <PackageReference Include="Autofac" Version="6.5.0" /> + <PackageReference Include="Microsoft.Extensions.Logging" Version="7.0.0" /> + <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="7.0.0" /> + <PackageReference Include="Moq" Version="4.18.4" /> </ItemGroup> <ItemGroup> - <ProjectReference Include="..\FitConnect\FitConnect.csproj"/> + <ProjectReference Include="..\FitConnect\FitConnect.csproj" /> </ItemGroup> <ItemGroup> diff --git a/readme.md b/readme.md index dc8a9f79e86f9a0c5c2b9d2a9923167c240daea3..1cf8bf7a6e8ea1930f27900fe5b51602a3d040c7 100644 --- a/readme.md +++ b/readme.md @@ -19,20 +19,18 @@ Das FIT-Connect .NET SDK bietet eine einfache Möglichkeit, sowohl einen Antrags ### OSX -__Anmerkung:__ -Bei einem Mac mit einem M1 chip, muss brew in der _x86-64_-Version installiert werden. +Für die Installation von OpenSSL muss die [Homebrew](https://brew.sh/) Paketverwaltung verwendet werden. +Zur installation von HomeBrew muss der folgende Befehl ausgeführt werden: -_Die Version x86_64 kann parallel zur arm64 Version installiert werden._ - -```sh -arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" +```bash +/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" ``` Auf OSX wird das SDK nur dann unterstützt, wenn OpenSSL auf dem System installiert ist. Zum Installieren von OpenSSL können Sie Homebrew verwenden: -```sh -brew install openssl@1.1 +```bash +brew install openssl ``` Die Environment-Variable ```DYLD_LIBRARY_PATH``` muss auf den Pfad zu OpenSSL verweisen. @@ -41,7 +39,7 @@ _Beispiele:_ ```sh export DYLD_LIBRARY_PATH=/usr/local/opt/openssl/lib -export DYLD_LIBRARY_PATH=/usr/local/opt/openssl@1.1/lib +export DYLD_LIBRARY_PATH=/opt/homebrew/opt/openssl@3/lib ``` ## Weitere Informationen zu FIT-Connect finden Sie hier: @@ -67,7 +65,7 @@ Hierfür muss der Client die Environment auswählen oder einen eigenen Environme ## Credentials ClientId und ClientSecret sind die Grundlage, um einen Token vom OAuth-Server abfragen zu können. -Die beiden Werte sind im [Self-Service Portal der Testumgebung von FIT-Connect](https://portal.auth-testing.FIT-Connect.fitko.dev/clients) zu erstellen. +Die beiden Werte sind im [Self-Service-Portal der Testumgebung von FIT-Connect](https://portal.auth-testing.FIT-Connect.fitko.dev/clients) zu erstellen. # Sender @@ -82,11 +80,12 @@ Das folgende Beispiel zeigt, wie Sie das SDK in einem sendenden System nutzen, u ### Plain Submission Builder -Wenn Antragsdaten im Backend des Senders (Onlinedienst) unverschlüsselt vorliegen, können diese mit dem `SubmissionBuilder` in ein verschlüsseltes Submission-Objekt umgewandelt werden. +Wenn Antragsdaten im Backend des Senders (Onlinedienst) unverschlüsselt vorliegen, können diese mit dem `SubmissionBuilder` in ein verschlüsseltes Submission-Objekt umgewandelt werden. Diese Umsetzungsvariante bietet eine geringere Sicherheit als die Umsetzung der Ende-zu-Ende-Verschlüsselung ab dem Endgerät der Antragsteller:in. Zudem erhöhen sich in dieser Umsetzungsvariante die IT-Sicherheits- und Datenschutzanforderungen an den Betrieb des Onlinedienstes, da Antragsdaten in dieser Umsetzungsvariante im Klartext durch das Backend des Onlinedienstes verarbeitet werden. -Eine Alternative stellt die Verschlüsselung von Antragsdaten im Frontend des Onlinedientes dar (siehe nächster Abschnitt *Encrypted Submission Builder*). +Eine Alternative stellt die Verschlüsselung von Antragsdaten im Frontend des Onlinedientes dar (siehe nächster Abschnitt +*Encrypted Submission Builder*). Weitere Informationen finden sich im Artikel [Verschlüsselte Übertragung von Antragsdaten](https://docs.fitko.de/fit-connect/docs/getting-started/encryption/) der FIT-Connect-Dokumentation. @@ -144,8 +143,8 @@ var encryptedSubmission = EncryptedSubmissionBuilder await Client.GetSender(FitConnectEnvironment.Testing, clientId, clientSecret, logger).SendAsync(encryptedSubmission); ``` -| **Wichtig** | -| ----------- | +| **Wichtig** | +|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Bei der Übernahme der Destination-ID (`destinationId`) und des Leistungsschlüssels (`leikaKey`) aus dem Frontend MUSS im Backend geprüft werden, ob ein Versand von Einreichungen dieser Leistung an den angegebenen Zustellpunkt zulässig ist. | ## Details @@ -228,6 +227,25 @@ Der Parameter ```logger``` ist optional und muss das Interface ```Microsoft.Exte Das Abschicken der Submission erfolgt mit diesem Aufruf. +### Abrufen des Event-Logs und des Status' + +Der `sender` verfügt über eine Methode `GetEventLogAsync()` und `GetStatusForSubmissionAsync()` mit denen der aktuelle Status der Submission beim Zustelldienst abgefragt werden kann. + +```csharp +var (status, problems) = await sender.GetStatusForSubmission(sentSubmission); +``` + +Die SentSubmission enthält alle nottwendigen Informationen, um den Status abzufragen. +Auch die `AthenticationTags` sind darin enthalten mit denen der Status überprüft werden kann. + +Der `status` beinhaltet den aktuellen _Zustand_ der Submission. +In den `problems` sind Rückmeldungen vom _Subscriber_ enthalten. + +Das gesamte `EventLog` kann ebenfalls abgerufen werden. +Dazu wird die Methode `sender.GetEventLogAsync(caseId, destinationId)` aufgerufen. +Eine Überprüfung der Gültikeit des Statuses erfolgt hier **nicht**. + + # Subscriber Das folgende Beispiel zeigt, wie Sie das SDK in einem empfangenden System nutzen, um einen Subscriber zu erzeugen, der Einreichungen von sendenden Systemen erhält. @@ -339,7 +357,6 @@ Akzeptiert die Submission und löscht die Submission, die auf dem Server gespeic Weist die Submission zurück. - ## Beispiel ```csharp