Skip to content
Snippets Groups Projects
Commit cddd0772 authored by Klaus Fischer's avatar Klaus Fischer
Browse files

WIP: Destination Parameter

parent 18f52de6
No related branches found
No related tags found
1 merge request!6Routing Api
......@@ -3,10 +3,17 @@ using FitConnect.Interfaces.Sender;
using FitConnect.Interfaces.Subscriber;
using FitConnect.Models;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Logging;
namespace FitConnect;
public static class Client {
static Client() {
#if DEBUG
IdentityModelEventSource.ShowPII = true;
#endif
}
/// <summary>
/// Creates the Sender Client
/// </summary>
......
......@@ -137,10 +137,12 @@ public class FitEncryption {
}
public static bool VerifyJwt(string signature, string secret) => VerifyJwt(signature,
new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret)));
public static bool VerifyJwt(string signature, string secret, out string? error,
ILogger? logger = null) => VerifyJwt(signature,
new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret)), out error, logger);
public static bool VerifyJwt(string signature, SecurityKey key) {
public static bool VerifyJwt(string signature, SecurityKey key, out string? error,
ILogger? logger = null) {
var tokenHandler = new JsonWebTokenHandler();
var result = tokenHandler.ValidateToken(signature, new TokenValidationParameters {
......@@ -154,7 +156,12 @@ public class FitEncryption {
});
Console.WriteLine(result.Exception?.Message);
error = result.Exception?.Message;
logger?.LogInformation("Checking with Key: {Key}", key.KeyId);
if (error != null)
logger?.LogWarning(error);
return result.IsValid;
}
}
......@@ -6,3 +6,15 @@ Accept: application/json
GET {{routing_api_url}}/v1/routes?leikaKey=99012070006000
Accept: application/json
### Get areas
GET {{routing_api_url}}/v1/routes?ars=064350014014&leikaKey=99123456760610
Accept: application/json
### Get Route
GET {{routing_api_url}}/v1/routes?ars=064350014014&leikaKey=99123456760610
###
GET https://submission-api-testing.fit-connect.fitko.dev/.well-known/jwks.json
Accept: application/json
Content-Type: application/json
### Get Destination
GET {{submission_api_url}}/.well-known/jwks.json
Accept: application/json
Content-Type: application/json
Authorization: Bearer {{token}}
### Get Destination infos
GET {{submission_api_url}}/v1/destinations/{{destinationId}}
Accept: application/json
......@@ -65,3 +72,8 @@ Authorization: Bearer {{token}}
"encryptedMetadata": "l3--gxZp131zyqCOWmdzxHiNySKGSlyOI63eIBoPDg1-f9v-GPFLCjNANFbW8y96orN0RYLsWQEa4JAV93lvz_caJQXMyFiE8VdRr7SjS4ivBfyizdplnnBQ2V_vZCL7t65GneogIF-xpiXF4zxOH6dY5BJxq9IC-6EkWK76fSa5xfe2k-SXDQXlqP6fWqkR2iECKO16cY5rrneMzkvC9nPNzeMKtlcnirQfKPEklK5Kp_6gLRT8nQrBUma5bDhctpOweSIiVeuv_zgHOzvxvuK6_Xoc1M0WHniR4y_qUA8YzLUI1-FfMu1N88TI0brcngbF4zVarQXv7q8gzGynEgTln11JrL0Fx87U_-Gfc5RUsjxMynEgZ8Qr72UpYF3HcMEg4xRTeivlWiOu4s9hvSyE2RJanp6amB68CPG-TUaS5tKbEPjHc5zmTOedUAgw-mfLOJNAleW_J-7L07pWCYxR0Jr5hVMFBBCuh1mbeMoW1kF1mfmDwT_X6U-cC_srvXQiSVk7kub0NJRpG9mx6FvHapVZRO709Luslj4Fw9d8Jnw6zw_MAxbBPOvNAVVm20Nqm66_aB4wv-qJDWA3SQZFW5dO4Zuh8eubLhOBes0jHTEFQSh6q4r1zVNYC1nSJUYzYpK9eaNa43oXF-HVp4rdXNaTyE6M0Vd5YgZwbOLrVS4QyvvURMgOcD5xRQCi6F89ZrAN09aoCAeaKuB-r5VuDfquYB5J6RMSXNLvXuHOR1iHwcC6EFvNnqzDystsDXJudPLSdiQJBszpOjM28DZgtl-I0hw7-FVKdTWlkB9IpbjTNMOdJcWMUCpoJIkAIiWYlAsmZ0K22mj_fFY08kPKyuEOJNBB_dDf2O_kF92PNY51I1Npa_PE2uXEaBp95772KvSdvn6fDri42iGJGIGS5cADQDHiDTYGrBsluzdLD6PKD4XBrGipM9jkWbTRNG8lY4lkNtUwtKU5rVDcbdstAivwdlTpeLKHVjPE-ITW-5QhM13HCgZ6eJPFpwpT4VpAUT4euikzoRccyJOYqkzKr1Z0JP-7kop-0GnKNZ1zBJEaEq_gf53lYInrV9f3EQM8ynQpp_0wMNwVU6_0xOjEMX5DMt2io_whkNEvuTa56A"
}
### Get well known keys
GET {{submission_api_url}}/.well-known/jwks.json
Accept: application/json
Content-Type: application/json
Authorization: Bearer {{token}}
\ No newline at end of file
using FitConnect.Encryption;
using System.Text;
using System.Text.Encodings.Web;
using FitConnect.Encryption;
using FitConnect.Models;
using FitConnect.Services;
using FitConnect.Services.Interfaces;
using IdentityModel;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.JsonWebTokens;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;
using Route = FitConnect.Services.Models.v1.Routes.Route;
namespace FitConnect;
public class Router : IRouter {
private readonly FitConnectEnvironment _environment;
private readonly ILogger? _logger;
private readonly IRouteService _routeService;
private readonly ISelfServicePortalService _selfServicePortalService;
public Router(FitConnectEnvironment environment, ILogger logger = null) {
public Router(FitConnectEnvironment environment, ILogger? logger = null) {
_environment = environment;
_logger = logger;
_routeService = new RouteService(environment.RoutingUrl, "v1", logger);
_selfServicePortalService = new SelfServicePortalService(environment.SspUrl, "v1", logger);
}
......@@ -23,16 +33,55 @@ public class Router : IRouter {
var routes = await _routeService.GetDestinationIdAsync(leiaKey, ags, ars, areaId);
if (skipValidation) return routes;
var validation = await _selfServicePortalService.GetSelfServiceValidationJwk();
var validation = await _selfServicePortalService.GetValidationJwk();
foreach (var route in routes) {
var token = new JsonWebToken(route.DestinationSignature);
FitEncryption.VerifyJwt(route.DestinationSignature,
validation.Keys.First(k => k.Kid == token.Kid));
var key = validation.Keys.First(k => k.Kid == token.Kid);
var verifyJwt =
FitEncryption.VerifyJwt(route.DestinationSignature, key, out var _, _logger);
var submissionKey =
await GetSubmissionServiceValidationJwk(route.DestinationParameters.SubmissionUrl);
// Get Key from SubmissionAPI
var parametersJson =
Base64Url.Encode(
Encoding.UTF8.GetBytes(
JsonConvert.SerializeObject(route.DestinationParameters)));
var signature =
route.DestinationParametersSignature.Replace("..", $".{parametersJson}.");
// KID to check is in signature header kid
var header = JsonConvert.DeserializeObject<dynamic>(
Base64UrlEncoder.Decode(route.DestinationParametersSignature.Split('.')[0])
);
var kid = (string)header.kid;
Console.WriteLine("Looking for key with kid: " + kid);
verifyJwt &= FitEncryption.VerifyJwt(signature,
submissionKey.Keys.First(k => k.Kid == kid), out var _, _logger);
if (!verifyJwt) {
throw new Exception("Invalid signature");
}
}
return routes;
}
/// <summary>
///
/// </summary>
/// <returns></returns>
private async Task<JsonWebKeySet> GetSubmissionServiceValidationJwk(string baseUrl) {
var client = new HttpClient() {
BaseAddress = new Uri(baseUrl),
};
var result = await client.GetAsync("/.well-known/jwks.json");
return new JsonWebKeySet(await result.Content.ReadAsStringAsync());
}
/// <summary>
/// Finding Areas
......@@ -48,10 +97,4 @@ public class Router : IRouter {
totalCount = dto?.TotalCount ?? 0;
return dto?.Areas ?? new List<Area>();
}
public async Task<List<Route>> FindDestinationsAsync(string leiaKey, string? ags = null,
string? ars = null,
string? areaId = null) {
throw new NotImplementedException();
}
}
using Jose;
using Microsoft.IdentityModel.Tokens;
namespace FitConnect.Services;
namespace FitConnect.Services.Interfaces;
public interface ISelfServicePortalService {
public Task<JsonWebKeySet> GetSelfServiceValidationJwk();
public Task<JsonWebKeySet> GetValidationJwk();
}
using FitConnect.Services.Interfaces;
using Jose;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
......@@ -9,7 +10,7 @@ public class SelfServicePortalService : RestCallService, ISelfServicePortalServi
ILogger? logger = null) : base($"{baseUrl}", logger) {
}
public async Task<JsonWebKeySet> GetSelfServiceValidationJwk() {
public async Task<JsonWebKeySet> GetValidationJwk() {
var content = await RestCallForString("/.well-known/jwks.json", HttpMethod.Get);
return new JsonWebKeySet(content);
}
......
......@@ -144,4 +144,8 @@ public class SubmissionService : RestCallService, ISubmissionService {
var events = await RestCall<EventLogDto>($"/cases/{caseId}/events", HttpMethod.Get);
return events.EventLog.ToList();
}
public async Task GetValidationJwk() {
throw new NotImplementedException();
}
}
using System;
using FitConnect.Encryption;
using FluentAssertions;
using Microsoft.IdentityModel.Logging;
using Microsoft.IdentityModel.Tokens;
using NUnit.Framework;
......@@ -7,11 +9,17 @@ namespace IntegrationTests;
[TestFixture]
public class JwtTokenValidation {
[OneTimeSetUp]
public void OneTimeSetUp() {
IdentityModelEventSource.ShowPII = true;
}
[Test]
public void ExampleFromWeb_passes() {
var result = FitEncryption.VerifyJwt(
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lLCBpcyBteSBuYW1lIiwiaWF0IjoxNTE2MjM5MDIyfQ.b-j_VvzOD6BAXc6jYOPl38eESJT4zzGrKlhX7j1gNfY",
"your-512-bit-secret");
"your-512-bit-secret", out var _);
result.Should().BeTrue();
}
......@@ -20,8 +28,10 @@ public class JwtTokenValidation {
public void ExampleFromWeb_fails() {
var result = FitEncryption.VerifyJwt(
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lLCBpcyBteSBuYW1lIiwiaWF0IjoxNTE2MjM5MDIyfQ.b-j_VvzOD6BAXc6jYOPl38eESJT4zzGrKlhX7j1gNfY",
"what_was_this?");
"what_was_this?",
out var errors);
Console.WriteLine($"Errors: {errors}");
result.Should().BeFalse();
}
......@@ -30,7 +40,8 @@ public class JwtTokenValidation {
var result = FitEncryption.VerifyJwt(
"eyJraWQiOiJhZUJVaFFTOHVhSnZ0ek1jVHlpRUFOM0tXNG02NXVEbUwwWDFBQUlxZENFIiwidHlwIjoiSldUIiwiYWxnIjoiUFM1MTIifQ.eyJzdWJtaXNzaW9uSG9zdCI6InN1Ym1pc3Npb24tYXBpLXRlc3RpbmcuZml0LWNvbm5lY3QuZml0a28uZGV2IiwiaXNzIjoiaHR0cHM6XC9cL3BvcnRhbC5hdXRoLXRlc3RpbmcuZml0LWNvbm5lY3QuZml0a28uZGV2Iiwic2VydmljZXMiOlt7ImdlYmlldElEcyI6WyJ1cm46ZGU6YnVuZDpkZXN0YXRpczpiZXZvZWxrZXJ1bmdzc3RhdGlzdGlrOnNjaGx1ZXNzZWw6cnM6MDY0MzUwMDE0MDE0Il0sImxlaXN0dW5nSURzIjpbInVybjpkZTpmaW06bGVpa2E6bGVpc3R1bmc6OTkxMjM0NTY3NjA2MTAiXX1dLCJkZXN0aW5hdGlvbklkIjoiZDQwZTdiMTMtZGE5OC00YjA5LTllMTYtYmJkNjFjYTgxNTEwIiwiaWF0IjoxNjUyMjkxMzkwLCJqdGkiOiJkOGI1NTM2NS1mNDMzLTRiNjMtYjg3Yi0xZWRiNTY3YzlmYWMifQ.RSdgZWBwPvsnlCajXF3Rh8uPDEKkAwgxNbzuO5HWCaAKroHQ8NQtoDGHe2iXFULR8ML7Ca5aHmGKR34CgGmdpxitbzDn_rjHe2WModuRclu8n_eEmGhMTAkcH1aQ8pcDnQAcfI44KPqQZ_D8X6IGqxOEMtoYiETay8OAN3Vzk1Ew9n4vrvK5r5eWIx-nu5uMtHhMqT7xg09jH0Ma4owfCiOrobEdM5fz9a5sWoi0aBTufEMR9ai-SuDR1ibNmwD7s7wYCdqCgaOtj-_dNbPNOYVUdHdRKMvPuFYEx8rs32mehgEEHX649m8QN0FAHsuXdPeagFv7ndceH2vrPPenKk6fz6W68fGZhfs6MzaoUBaz2p3uZJdTCk5gPrJu46TBW0uPEI8dY8Aw_SNMGWsyfviAzjbuhJ3JBoKk8tjPjkERWF9hovlrXu9l9s-jbAn-U-PYWsLYNAaCqvMEGLNmyTnsEMQuKWCQDr1mi0K8QqPiPNDe4NHmy49ObcesLB64LIE5did6XVUGOu3qOACg-s9dN0tFmqEw_-CWOhiWoAQRcu4uyzjCUWKoa6zpw_G3I5STzV328bwHf4hBDnTzZ8PH9OwG0vwqX1jeGdqYz3fWEz8gdU_N18t10393BYJy1tEggCnZzIVBqjQXAjV4pcI6G19D-xT3ITonxdMTAZw",
new JsonWebKey(
"{\"alg\":\"PS512\",\"e\":\"AQAB\",\"key_ops\":[\"verify\"],\"kid\":\"aeBUhQS8uaJvtzMcTyiEAN3KW4m65uDmL0X1AAIqdCE\",\"kty\":\"RSA\",\"n\":\"4Y0sJhadfrQnNZXeS7Pqh73FvtFPXLvLw11h7OiZM0DlqvRNgoYHO5k-kxJKOVCaFek0LjKM1_VQxMVpdChCkHeapdTg60oQTQZj3pG0boR3LStbqN3hNEx_JZC4aHH16kau0vqBBPiOOoq-ExUz-hXz_GMLsp9QVqIkw9okO_tzNPjQOo--GM8r4eSsKzgSHZzmepc9Gfk16eraGicBevlkclk32TmWIE_ErD31dtVbBlK-7GG2NUe-o_5rkiCJ2EwKRHZlLkBYJkkj_IjeUdKc4dawXoE8L83DSBPyapX47_L1VHTnT0hJdOVe6WHtvzzpusZ0Au-YDhp6LSwXnU9d0-VzBJmQvtrep1FM0d9aQrz0e0lVf8wCn13VdKO_FBZw9D7i0XRhF8JqQRblqhcCY7UGshbTTM8HORMFONHFmSQm10qfV29PLmztOhIuubMyYe1DPnlfRkpn5jnt8IPoopl6MliDKSc3m4dgG23KylBpTLr3U-XGQrTlerjrYh4t1LXiJ-jQhLefkak_WnExZJSXv601BgmbGj3GdIhS6lxdMX62cOuwKLVISOmHHxvimpQwhtYwiFR9OmGoKVgtCQ5eMKLwGWVwXSvUJ5YXH-yUyNW1_vOrt0DAtYmXwS_Ij0bMg9WoXKJ-5NtQpnnIzw1lr5bW5fNn2TgWpHk\"}"));
"{\"alg\":\"PS512\",\"e\":\"AQAB\",\"key_ops\":[\"verify\"],\"kid\":\"aeBUhQS8uaJvtzMcTyiEAN3KW4m65uDmL0X1AAIqdCE\",\"kty\":\"RSA\",\"n\":\"4Y0sJhadfrQnNZXeS7Pqh73FvtFPXLvLw11h7OiZM0DlqvRNgoYHO5k-kxJKOVCaFek0LjKM1_VQxMVpdChCkHeapdTg60oQTQZj3pG0boR3LStbqN3hNEx_JZC4aHH16kau0vqBBPiOOoq-ExUz-hXz_GMLsp9QVqIkw9okO_tzNPjQOo--GM8r4eSsKzgSHZzmepc9Gfk16eraGicBevlkclk32TmWIE_ErD31dtVbBlK-7GG2NUe-o_5rkiCJ2EwKRHZlLkBYJkkj_IjeUdKc4dawXoE8L83DSBPyapX47_L1VHTnT0hJdOVe6WHtvzzpusZ0Au-YDhp6LSwXnU9d0-VzBJmQvtrep1FM0d9aQrz0e0lVf8wCn13VdKO_FBZw9D7i0XRhF8JqQRblqhcCY7UGshbTTM8HORMFONHFmSQm10qfV29PLmztOhIuubMyYe1DPnlfRkpn5jnt8IPoopl6MliDKSc3m4dgG23KylBpTLr3U-XGQrTlerjrYh4t1LXiJ-jQhLefkak_WnExZJSXv601BgmbGj3GdIhS6lxdMX62cOuwKLVISOmHHxvimpQwhtYwiFR9OmGoKVgtCQ5eMKLwGWVwXSvUJ5YXH-yUyNW1_vOrt0DAtYmXwS_Ij0bMg9WoXKJ-5NtQpnnIzw1lr5bW5fNn2TgWpHk\"}"),
out var _);
result.Should().BeTrue();
}
......@@ -41,8 +52,10 @@ public class JwtTokenValidation {
var result = FitEncryption.VerifyJwt(
"eyJraWQiOiJhZUJVaFFTOHVhSnZ0ek1jVHlpRUFOM0tXNG02NXVEbUwwWDFBQUlxZENFIiwidHlwIjoiSldUIiwiYWxnIjoiUFM1MTIifQ.eyJzdWJtaXNzaW9uSG9zdCI6InN1Ym1pc3Npb24tYXBpLXRlc3RpbmcuZml0LWNvbm5lY3QuZml0a28uZGV2IiwiaXNzIjoiaHR0cHM6XC9cL3BvcnRhbC5hdXRoLXRlc3RpbmcuZml0LWNvbm5lY3QuZml0a28uZGV2Iiwic2VydmljZXMiOlt7ImdlYmlldElEcyI6WyJ1cm46ZGU6YnVuZDpkZXN0YXRpczpiZXZvZWxrZXJ1bmdzc3RhdGlzdGlrOnNjaGx1ZXNzZWw6cnM6MDY0MzUwMDE0MDE0Il0sImxlaXN0dW5nSURzIjpbInVybjpkZTpmaW06bGVpa2E6bGVpc3R1bmc6OTkxMjM0NTY3NjA2MTAiXX1dLCJkZXN0aW5hdGlvbklkIjoiZDQwZTdiMTMtZGE5OC00YjA5LTllMTYtYmJkNjFjYTgxNTEwIiwiaWF0IjoxNjUyMjkxMzkwLCJqdGkiOiJkOGI1NTM2NS1mNDMzLTRiNjMtYjg3Yi0xZWRiNTY3YzlmYWMifQ.RSdgZWBwPvsnlCajXF3Rh8uPDEKkAwgxNbzuO5HWCaAKroHQ8NQtoDGHe2iXFULR8ML7Ca5aHmGKR34CgGmdpxitbzDn_rjHe2WModuRclu8n_eEmGhMTAkcH1aQ8pcDnQAcfI44KPqQZ_D8X6IGqxOEMtoYiETay8OAN3Vzk1Ew9n4vrvK5r5eWIx-nu5uMtHhMqT7xg09jH0Ma4owfCiOrobEdM5fz9a5sWoi0aBTufEMR9ai-SuDR1ibNmwD7s7wYCdqCgaOtj-_dNbPNOYVUdHdRKMvPuFYEx8rs32mehgEEHX649m8QN0FAHsuXdPeagFv7ndceH2vrPPenKk6fz6W68fGZhfs6MzaoUBaz2p3uZJdTCk5gPrJu46TBW0uPEI8dY8Aw_SNMGWsyfviAzjbuhJ3JBoKk8tjPjkERWF9hovlrXu9l9s-jbAn-U-PYWsLYNAaCqvMEGLNmyTnsEMQuKWCQDr1mi0K8QqPiPNDe4NHmy49ObcesLB64LIE5did6XVUGOu3qOACg-s9dN0tFmqEw_-CWOhiWoAQRcu4uyzjCUWKoa6zpw_G3I5STzV328bwHf4hBDnTzZ8PH9OwG0vwqX1jeGdqYz3fWEz8gdU_N18t10393BYJy1tEggCnZzIVBqjQXAjV4pcI6G19D-xT3ITonxdMTAZw",
new JsonWebKey(
"{\"alg\":\"PS512\",\"e\":\"AQAB\",\"key_ops\":[\"verify\"],\"kid\":\"aeBUhQS8uaJvtzMcTyiEAN3KW4m65uDmL0X1AAIqdCE\",\"kty\":\"RSA\",\"n\":\"4Y0KJhadfrQnNZXeS7Pqh73FvtFPXLvLw11h7OiZM0DlqvRNgoYHO5k-kxJKOVCaFek0LjKM1_VQxMVpdChCkHeapdTg60oQTQZj3pG0boR3LStbqN3hNEx_JZC4aHH16kau0vqBBPiOOoq-ExUz-hXz_GMLsp9QVqIkw9okO_tzNPjQOo--GM8r4eSsKzgSHZzmepc9Gfk16eraGicBevlkclk32TmWIE_ErD31dtVbBlK-7GG2NUe-o_5rkiCJ2EwKRHZlLkBYJkkj_IjeUdKc4dawXoE8L83DSBPyapX47_L1VHTnT0hJdOVe6WHtvzzpusZ0Au-YDhp6LSwXnU9d0-VzBJmQvtrep1FM0d9aQrz0e0lVf8wCn13VdKO_FBZw9D7i0XRhF8JqQRblqhcCY7UGshbTTM8HORMFONHFmSQm10qfV29PLmztOhIuubMyYe1DPnlfRkpn5jnt8IPoopl6MliDKSc3m4dgG23KylBpTLr3U-XGQrTlerjrYh4t1LXiJ-jQhLefkak_WnExZJSXv601BgmbGj3GdIhS6lxdMX62cOuwKLVISOmHHxvimpQwhtYwiFR9OmGoKVgtCQ5eMKLwGWVwXSvUJ5YXH-yUyNW1_vOrt0DAtYmXwS_Ij0bMg9WoXKJ-5NtQpnnIzw1lr5bW5fNn2TgWpHk\"}"));
"{\"alg\":\"PS512\",\"e\":\"AQAB\",\"key_ops\":[\"verify\"],\"kid\":\"aeBUhQS8uaJvtzMcTyiEAN3KW4m65uDmL0X1AAIqdCE\",\"kty\":\"RSA\",\"n\":\"4Y0KJhadfrQnNZXeS7Pqh73FvtFPXLvLw11h7OiZM0DlqvRNgoYHO5k-kxJKOVCaFek0LjKM1_VQxMVpdChCkHeapdTg60oQTQZj3pG0boR3LStbqN3hNEx_JZC4aHH16kau0vqBBPiOOoq-ExUz-hXz_GMLsp9QVqIkw9okO_tzNPjQOo--GM8r4eSsKzgSHZzmepc9Gfk16eraGicBevlkclk32TmWIE_ErD31dtVbBlK-7GG2NUe-o_5rkiCJ2EwKRHZlLkBYJkkj_IjeUdKc4dawXoE8L83DSBPyapX47_L1VHTnT0hJdOVe6WHtvzzpusZ0Au-YDhp6LSwXnU9d0-VzBJmQvtrep1FM0d9aQrz0e0lVf8wCn13VdKO_FBZw9D7i0XRhF8JqQRblqhcCY7UGshbTTM8HORMFONHFmSQm10qfV29PLmztOhIuubMyYe1DPnlfRkpn5jnt8IPoopl6MliDKSc3m4dgG23KylBpTLr3U-XGQrTlerjrYh4t1LXiJ-jQhLefkak_WnExZJSXv601BgmbGj3GdIhS6lxdMX62cOuwKLVISOmHHxvimpQwhtYwiFR9OmGoKVgtCQ5eMKLwGWVwXSvUJ5YXH-yUyNW1_vOrt0DAtYmXwS_Ij0bMg9WoXKJ-5NtQpnnIzw1lr5bW5fNn2TgWpHk\"}"),
out var errors);
Console.WriteLine($"Errors: {errors}");
result.Should().BeFalse();
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment