From a0d98b4d7703133616e329f381a5a4ff8bc77029 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Thu, 19 Feb 2026 22:19:49 +0100 Subject: [PATCH] quick fix --- .gitignore | 7 +-- .../Controllers/ParticipantController.cs | 29 +++++------ src/Registration/Registration.API/Program.cs | 52 ++++++++++++------- .../Registration.API/Services/AuthService.cs | 10 ++-- .../Services/VbytesParticipantRelayService.cs | 8 ++- .../Services/VbytesRelayServiceBase.cs | 12 ++--- .../Services/VbytesVolunteerRelayService.cs | 4 +- src/Web/lan-frontend/app/register/page.tsx | 14 ++--- 8 files changed, 72 insertions(+), 64 deletions(-) diff --git a/.gitignore b/.gitignore index 216e602..e7b86cc 100644 --- a/.gitignore +++ b/.gitignore @@ -6,9 +6,10 @@ # dotenv files .env -*www.api.vbytes.se.key -*www.api.vbytes.se.csr -*www.api.vbytes.se.crt +*.key +*.csr +*.crt +*.pfx # User-specific files *.rsuser diff --git a/src/Registration/Registration.API/Controllers/ParticipantController.cs b/src/Registration/Registration.API/Controllers/ParticipantController.cs index d666148..a38f8fb 100644 --- a/src/Registration/Registration.API/Controllers/ParticipantController.cs +++ b/src/Registration/Registration.API/Controllers/ParticipantController.cs @@ -2,25 +2,24 @@ using Microsoft.AspNetCore.Mvc; using Registration.API.Services; using Registration.Domain.Models; -namespace Registration.API.Controllers +namespace Registration.API.Controllers; + +[Route("api/[controller]")] +[ApiController] +public class ParticipantController(IVbytesParticipantRelayService relayService) : ControllerBase { - [Route("api/[controller]")] - [ApiController] - public class ParticipantController(IVbytesParticipantRelayService relayService) : ControllerBase + private readonly IVbytesParticipantRelayService _relayService = relayService; + + [HttpPost("register")] + public async Task RegisterForLan([FromBody] Participant participant, CancellationToken cancellationToken) { - private readonly IVbytesParticipantRelayService _relayService = relayService; + var result = await _relayService.RegisterParticipantAsync(participant, cancellationToken); - [HttpPost("register")] - public async Task RegisterForLan([FromBody] Participant participant, CancellationToken cancellationToken) + if (result.StatusCode == 200 && !result.Message.Contains("401")) { - var result = await _relayService.RegisterParticipantAsync(participant, cancellationToken); - - if (result.Success) - { - return Ok(); - } - - return StatusCode(result.StatusCode, new { message = result.Message }); + return Ok(); } + + return Unauthorized(); } } diff --git a/src/Registration/Registration.API/Program.cs b/src/Registration/Registration.API/Program.cs index 8420c9b..e6c479f 100644 --- a/src/Registration/Registration.API/Program.cs +++ b/src/Registration/Registration.API/Program.cs @@ -12,16 +12,42 @@ builder.Services.AddScoped(); var relayOptions = builder.Configuration.GetSection("VbytesRelay").Get() ?? throw new InvalidOperationException("VbytesRelay configuration section is missing."); -builder.Services.Configure(builder.Configuration.GetSection("VbytesRelay")); - - var certificate = X509CertificateLoader.LoadPkcs12FromFile( relayOptions.ClientCertificatePfxPath, password: null); -builder.Services.AddHttpClient(VbytesParticipantRelayService.HttpClientName, client => +builder.Services.AddSingleton(sp => { - client.BaseAddress = new Uri(relayOptions.BaseUrl); - client.Timeout = TimeSpan.FromSeconds(30); + var handler = new HttpClientHandler(); + handler.ClientCertificates.Add(certificate); + return handler; +}); + +var authApiOptions = builder.Configuration.GetSection("AuthApi").Get() + ?? throw new InvalidOperationException("AuthApi configuration section is missing."); + +builder.Services.Configure(builder.Configuration.GetSection("VbytesRelay")); + + +builder.Services.AddHttpClient(o => +{ + o.BaseAddress = new Uri(relayOptions.BaseUrl) ?? + throw new InvalidOperationException("BaseUrl is missing in VbytesRelay configuration."); + o.Timeout = TimeSpan.FromSeconds(30); +}) +.ConfigurePrimaryHttpMessageHandler(sp => sp.GetRequiredService()); + +builder.Services.AddHttpClient(o => +{ + o.BaseAddress = new Uri(relayOptions.BaseUrl); + o.Timeout = TimeSpan.FromSeconds(30); +}) +.ConfigurePrimaryHttpMessageHandler(sp => sp.GetRequiredService()); + +builder.Services.Configure(builder.Configuration.GetSection("AuthApi")); +builder.Services.AddHttpClient(o => +{ + o.BaseAddress = new Uri(authApiOptions.BaseUrl); + o.Timeout = TimeSpan.FromSeconds(10); }) .ConfigurePrimaryHttpMessageHandler(() => { @@ -30,20 +56,6 @@ builder.Services.AddHttpClient(VbytesParticipantRelayService.HttpClientName, cli return handler; }); -builder.Services.AddScoped(); -builder.Services.AddScoped(); - -var authApiOptions = builder.Configuration.GetSection("AuthApi").Get() - ?? throw new InvalidOperationException("AuthApi configuration section is missing."); - -builder.Services.Configure(builder.Configuration.GetSection("AuthApi")); -builder.Services.AddHttpClient(AuthService.HttpClientName, client => -{ - client.BaseAddress = new Uri(authApiOptions.BaseUrl); - client.Timeout = TimeSpan.FromSeconds(10); -}); -builder.Services.AddScoped(); - builder.Services.AddControllers(); var app = builder.Build(); diff --git a/src/Registration/Registration.API/Services/AuthService.cs b/src/Registration/Registration.API/Services/AuthService.cs index 6da411f..17e7530 100644 --- a/src/Registration/Registration.API/Services/AuthService.cs +++ b/src/Registration/Registration.API/Services/AuthService.cs @@ -3,20 +3,18 @@ using Registration.API.Configuration; namespace Registration.API.Services; -public class AuthService(IHttpClientFactory httpClientFactory, IOptions options) : IAuthService +public class AuthService(HttpClient httpClient, IOptions options) : IAuthService { public const string HttpClientName = "AuthApi"; - - private readonly IHttpClientFactory _httpClientFactory = httpClientFactory; + private readonly HttpClient _httpClient = httpClient; private readonly AuthApiOptions _options = options.Value; public async Task IsMemberAsync(string ssn, CancellationToken cancellationToken = default) { - var client = _httpClientFactory.CreateClient(HttpClientName); - var response = await client.PostAsJsonAsync( + var response = await _httpClient.PostAsJsonAsync( _options.ValidatePath, new { ssn }, cancellationToken); - return response.IsSuccessStatusCode; + return (int)response.StatusCode == StatusCodes.Status200OK; } } diff --git a/src/Registration/Registration.API/Services/VbytesParticipantRelayService.cs b/src/Registration/Registration.API/Services/VbytesParticipantRelayService.cs index f8128bb..ec8437c 100644 --- a/src/Registration/Registration.API/Services/VbytesParticipantRelayService.cs +++ b/src/Registration/Registration.API/Services/VbytesParticipantRelayService.cs @@ -6,10 +6,10 @@ using Registration.Domain.Models; namespace Registration.API.Services; public class VbytesParticipantRelayService( - IHttpClientFactory httpClientFactory, + HttpClient httpClient, IOptions options, ILogger logger) - : VbytesRelayServiceBase(httpClientFactory, options), IVbytesParticipantRelayService + : VbytesRelayServiceBase(httpClient, options), IVbytesParticipantRelayService { public const string HttpClientName = "VbytesRelay"; @@ -21,6 +21,7 @@ public class VbytesParticipantRelayService( if (configError is not null) { _logger.LogWarning("Relay configuration invalid: {Message}", configError.Message); + return configError; } @@ -31,16 +32,19 @@ public class VbytesParticipantRelayService( { var result = await SendAsync(Options.ParticipantRegisterPath, payload, cancellationToken); _logger.LogInformation("Relay response: {StatusCode} - {Message}", result.StatusCode, result.Message); + return result; } catch (TaskCanceledException) { _logger.LogWarning("Relay timed out calling {Path}", Options.ParticipantRegisterPath); + return new VbytesRelayResult(false, StatusCodes.Status504GatewayTimeout, "Upstream timeout."); } catch (Exception ex) { _logger.LogError(ex, "VBytes participant relay exception."); + return new VbytesRelayResult(false, StatusCodes.Status502BadGateway, "Upstream relay failed."); } } diff --git a/src/Registration/Registration.API/Services/VbytesRelayServiceBase.cs b/src/Registration/Registration.API/Services/VbytesRelayServiceBase.cs index aca99fe..999cd75 100644 --- a/src/Registration/Registration.API/Services/VbytesRelayServiceBase.cs +++ b/src/Registration/Registration.API/Services/VbytesRelayServiceBase.cs @@ -1,20 +1,18 @@ -using System.Net.Http.Json; +using System.Text.Json; using Microsoft.Extensions.Options; using Registration.API.Configuration; namespace Registration.API.Services; public abstract class VbytesRelayServiceBase( - IHttpClientFactory httpClientFactory, + HttpClient httpClient, IOptions options) { - private readonly IHttpClientFactory _httpClientFactory = httpClientFactory; + private readonly HttpClient _httpClient = httpClient; protected readonly VbytesRelayOptions Options = options.Value; protected async Task SendAsync(string path, object payload, CancellationToken cancellationToken) { - var client = _httpClientFactory.CreateClient(VbytesParticipantRelayService.HttpClientName); - using var request = new HttpRequestMessage(HttpMethod.Post, BuildPath(path)) { Content = JsonContent.Create(payload) @@ -22,13 +20,13 @@ public abstract class VbytesRelayServiceBase( request.Headers.TryAddWithoutValidation(Options.ApiKeyHeaderName, Options.ApiKey); - using var response = await client.SendAsync(request, cancellationToken); + using var response = await _httpClient.SendAsync(request, cancellationToken); var body = await response.Content.ReadAsStringAsync(cancellationToken); if (response.IsSuccessStatusCode) { Console.WriteLine($"[DEBUG] Relay success body: {body}"); - return new VbytesRelayResult(true, StatusCodes.Status200OK, "Request relayed successfully."); + return new VbytesRelayResult(true, StatusCodes.Status200OK, body); } var statusCode = (int)response.StatusCode; diff --git a/src/Registration/Registration.API/Services/VbytesVolunteerRelayService.cs b/src/Registration/Registration.API/Services/VbytesVolunteerRelayService.cs index bf99067..52f11a1 100644 --- a/src/Registration/Registration.API/Services/VbytesVolunteerRelayService.cs +++ b/src/Registration/Registration.API/Services/VbytesVolunteerRelayService.cs @@ -6,10 +6,10 @@ using Registration.Domain.Models; namespace Registration.API.Services; public class VbytesVolunteerRelayService( - IHttpClientFactory httpClientFactory, + HttpClient httpClient, IOptions options, ILogger logger) - : VbytesRelayServiceBase(httpClientFactory, options), IVbytesVolunteerRelayService + : VbytesRelayServiceBase(httpClient, options), IVbytesVolunteerRelayService { private readonly ILogger _logger = logger; diff --git a/src/Web/lan-frontend/app/register/page.tsx b/src/Web/lan-frontend/app/register/page.tsx index 8fdbdf4..af109e2 100644 --- a/src/Web/lan-frontend/app/register/page.tsx +++ b/src/Web/lan-frontend/app/register/page.tsx @@ -46,27 +46,19 @@ export default function RegisterPage() { setMessage({ type: "info", text: "Processing your registration..." }); try { - // 1. Check if the SSN has already been registered for the LAN // Returns Ok (200) if NOT registered, Conflict (409) if registered const checkRes = await fetch(`/api/Registration/registered/${formData.ssn}`); - + if (checkRes.status === 409) { setMessage({ type: "error", text: "This SSN is already registered for the LAN." }); setIsSubmitting(false); return; } - // 2. Check membership status via GET Registration register // Returns 200 (Ok) if member, 404 (NotFound) if not const validateRes = await fetch(`/api/Registration/register/${formData.ssn}`); const isMember = validateRes.ok; - // 3. Register the SSN in the membership system via POST - await fetch(`/api/Registration/register/${formData.ssn}`, { - method: "POST", - }); - - // 4. Register the participant for the event const { ssn, ...participantData } = formData; const finalPayload = { ...participantData, @@ -83,6 +75,10 @@ export default function RegisterPage() { if (response.ok) { setMessage({ type: "success", text: "Registration complete! You are now registered for the LAN." }); + + await fetch(`/api/Registration/register/${formData.ssn}`, { + method: "POST", + }); } else { const errorData = await response.json(); setMessage({ type: "error", text: errorData.message || "Event registration failed." });