From f6dc64b88b7dee543e73b633f5dc0ad3d7f6078f Mon Sep 17 00:00:00 2001 From: Aaron Po Date: Mon, 2 Mar 2026 22:35:18 -0500 Subject: [PATCH] Format API directory --- .csharpierrc.json | 20 +- src/Core/API/API.Core/API.Core.csproj | 69 ++++--- .../JwtAuthenticationHandler.cs | 78 ++++--- .../API/API.Core/Contracts/Auth/AuthDTO.cs | 4 +- .../API.Core/Contracts/Auth/RefreshToken.cs | 14 +- .../API.Core/Controllers/AuthController.cs | 4 +- .../Controllers/ProtectedController.cs | 32 ++- src/Core/API/API.Core/Program.cs | 8 +- src/Core/API/API.Specs/API.Specs.csproj | 76 +++---- .../API/API.Specs/Steps/ApiGeneralSteps.cs | 12 +- src/Core/API/API.Specs/Steps/AuthSteps.cs | 190 ++++++++++++++---- 11 files changed, 324 insertions(+), 183 deletions(-) diff --git a/.csharpierrc.json b/.csharpierrc.json index 0e17843..afd1cb3 100644 --- a/.csharpierrc.json +++ b/.csharpierrc.json @@ -1,9 +1,19 @@ { + "$schema": "https://json.schemastore.org/csharpier.json", + "printWidth": 80, "useTabs": false, - "tabWidth": 4, - "endOfLine": "auto", - "indentStyle": "space", - "lineEndings": "auto", - "wrapLineLength": 80 + "indentSize": 4, + "endOfLine": "lf", + + "overrides": [ + { + "files": "*.xml", + "indentSize": 2 + }, + { + "files": "*.csx", + "printWidth": 80 + } + ] } diff --git a/src/Core/API/API.Core/API.Core.csproj b/src/Core/API/API.Core/API.Core.csproj index 739d159..61c6ba5 100644 --- a/src/Core/API/API.Core/API.Core.csproj +++ b/src/Core/API/API.Core/API.Core.csproj @@ -1,39 +1,42 @@ - - net10.0 - enable - enable - API.Core - Linux - + + net10.0 + enable + enable + API.Core + Linux + - - - - - + + + + + - - - + + + - - - - - - - - - - + + + + + + + + + + - - - .dockerignore - - + + + .dockerignore + + diff --git a/src/Core/API/API.Core/Authentication/JwtAuthenticationHandler.cs b/src/Core/API/API.Core/Authentication/JwtAuthenticationHandler.cs index 514f0e4..cb07381 100644 --- a/src/Core/API/API.Core/Authentication/JwtAuthenticationHandler.cs +++ b/src/Core/API/API.Core/Authentication/JwtAuthenticationHandler.cs @@ -14,39 +14,57 @@ public class JwtAuthenticationHandler( IConfiguration configuration ) : AuthenticationHandler(options, logger, encoder) { - protected override async Task HandleAuthenticateAsync() - { - // Get the JWT secret from configuration - var secret = configuration["Jwt:SecretKey"] - ?? throw new InvalidOperationException("JWT SecretKey is not configured"); + protected override async Task HandleAuthenticateAsync() + { + // Get the JWT secret from configuration + var secret = + configuration["Jwt:SecretKey"] + ?? throw new InvalidOperationException( + "JWT SecretKey is not configured" + ); - // Check if Authorization header exists - if (!Request.Headers.TryGetValue("Authorization", out var authHeaderValue)) - { - return AuthenticateResult.Fail("Authorization header is missing"); - } + // Check if Authorization header exists + if ( + !Request.Headers.TryGetValue( + "Authorization", + out var authHeaderValue + ) + ) + { + return AuthenticateResult.Fail("Authorization header is missing"); + } - var authHeader = authHeaderValue.ToString(); - if (!authHeader.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase)) - { - return AuthenticateResult.Fail("Invalid authorization header format"); - } + var authHeader = authHeaderValue.ToString(); + if ( + !authHeader.StartsWith( + "Bearer ", + StringComparison.OrdinalIgnoreCase + ) + ) + { + return AuthenticateResult.Fail( + "Invalid authorization header format" + ); + } - var token = authHeader.Substring("Bearer ".Length).Trim(); + var token = authHeader.Substring("Bearer ".Length).Trim(); - try - { - var claimsPrincipal = await tokenInfrastructure.ValidateJwtAsync(token, secret); - var ticket = new AuthenticationTicket(claimsPrincipal, Scheme.Name); - return AuthenticateResult.Success(ticket); - } - catch (Exception ex) - { - return AuthenticateResult.Fail($"Token validation failed: {ex.Message}"); - } - } + try + { + var claimsPrincipal = await tokenInfrastructure.ValidateJwtAsync( + token, + secret + ); + var ticket = new AuthenticationTicket(claimsPrincipal, Scheme.Name); + return AuthenticateResult.Success(ticket); + } + catch (Exception ex) + { + return AuthenticateResult.Fail( + $"Token validation failed: {ex.Message}" + ); + } + } } -public class JwtAuthenticationOptions : AuthenticationSchemeOptions -{ -} +public class JwtAuthenticationOptions : AuthenticationSchemeOptions { } diff --git a/src/Core/API/API.Core/Contracts/Auth/AuthDTO.cs b/src/Core/API/API.Core/Contracts/Auth/AuthDTO.cs index 849f4e1..124ae2e 100644 --- a/src/Core/API/API.Core/Contracts/Auth/AuthDTO.cs +++ b/src/Core/API/API.Core/Contracts/Auth/AuthDTO.cs @@ -18,6 +18,4 @@ public record RegistrationPayload( bool ConfirmationEmailSent ); -public record ConfirmationPayload( - Guid UserAccountId, - DateTime ConfirmedDate); +public record ConfirmationPayload(Guid UserAccountId, DateTime ConfirmedDate); diff --git a/src/Core/API/API.Core/Contracts/Auth/RefreshToken.cs b/src/Core/API/API.Core/Contracts/Auth/RefreshToken.cs index e697656..0914d52 100644 --- a/src/Core/API/API.Core/Contracts/Auth/RefreshToken.cs +++ b/src/Core/API/API.Core/Contracts/Auth/RefreshToken.cs @@ -4,16 +4,16 @@ namespace API.Core.Contracts.Auth; public record RefreshTokenRequest { - public string RefreshToken { get; init; } = default!; + public string RefreshToken { get; init; } = default!; } public class RefreshTokenRequestValidator : AbstractValidator { - public RefreshTokenRequestValidator() - { - RuleFor(x => x.RefreshToken) - .NotEmpty() - .WithMessage("Refresh token is required"); - } + public RefreshTokenRequestValidator() + { + RuleFor(x => x.RefreshToken) + .NotEmpty() + .WithMessage("Refresh token is required"); + } } diff --git a/src/Core/API/API.Core/Controllers/AuthController.cs b/src/Core/API/API.Core/Controllers/AuthController.cs index 0129b9a..e9ce3b4 100644 --- a/src/Core/API/API.Core/Controllers/AuthController.cs +++ b/src/Core/API/API.Core/Controllers/AuthController.cs @@ -87,9 +87,7 @@ namespace API.Core.Controllers [FromBody] RefreshTokenRequest req ) { - var rtn = await tokenService.RefreshTokenAsync( - req.RefreshToken - ); + var rtn = await tokenService.RefreshTokenAsync(req.RefreshToken); return Ok( new ResponseBody diff --git a/src/Core/API/API.Core/Controllers/ProtectedController.cs b/src/Core/API/API.Core/Controllers/ProtectedController.cs index e14d658..6b6d8b7 100644 --- a/src/Core/API/API.Core/Controllers/ProtectedController.cs +++ b/src/Core/API/API.Core/Controllers/ProtectedController.cs @@ -1,7 +1,7 @@ +using System.Security.Claims; using API.Core.Contracts.Common; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -using System.Security.Claims; namespace API.Core.Controllers; @@ -10,22 +10,18 @@ namespace API.Core.Controllers; [Authorize(AuthenticationSchemes = "JWT")] public class ProtectedController : ControllerBase { - [HttpGet] - public ActionResult> Get() - { - var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value; - var username = User.FindFirst(ClaimTypes.Name)?.Value; + [HttpGet] + public ActionResult> Get() + { + var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value; + var username = User.FindFirst(ClaimTypes.Name)?.Value; - return Ok( - new ResponseBody - { - Message = "Protected endpoint accessed successfully", - Payload = new - { - userId, - username - } - } - ); - } + return Ok( + new ResponseBody + { + Message = "Protected endpoint accessed successfully", + Payload = new { userId, username }, + } + ); + } } diff --git a/src/Core/API/API.Core/Program.cs b/src/Core/API/API.Core/Program.cs index 66fa12b..e186dba 100644 --- a/src/Core/API/API.Core/Program.cs +++ b/src/Core/API/API.Core/Program.cs @@ -72,8 +72,12 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); // Configure JWT Authentication -builder.Services.AddAuthentication("JWT") - .AddScheme("JWT", options => { }); +builder + .Services.AddAuthentication("JWT") + .AddScheme( + "JWT", + options => { } + ); builder.Services.AddAuthorization(); diff --git a/src/Core/API/API.Specs/API.Specs.csproj b/src/Core/API/API.Specs/API.Specs.csproj index e0a6e42..705f4cb 100644 --- a/src/Core/API/API.Specs/API.Specs.csproj +++ b/src/Core/API/API.Specs/API.Specs.csproj @@ -1,46 +1,46 @@ - - net10.0 - enable - enable - false - API.Specs - + + net10.0 + enable + enable + false + API.Specs + - - - - - - + + + + + + - - - - + + + + - - - + + + - - - - + + + + - - - + + + - - - - + + + + diff --git a/src/Core/API/API.Specs/Steps/ApiGeneralSteps.cs b/src/Core/API/API.Specs/Steps/ApiGeneralSteps.cs index 0097f3e..44273f4 100644 --- a/src/Core/API/API.Specs/Steps/ApiGeneralSteps.cs +++ b/src/Core/API/API.Specs/Steps/ApiGeneralSteps.cs @@ -196,8 +196,14 @@ public class ApiGeneralSteps(ScenarioContext scenario) field ); var actualValue = value.GetString(); - actualValue.Should().Contain(expectedSubstring, - "Expected field '{0}' to contain '{1}' but was '{2}'", - field, expectedSubstring, actualValue); + actualValue + .Should() + .Contain( + expectedSubstring, + "Expected field '{0}' to contain '{1}' but was '{2}'", + field, + expectedSubstring, + actualValue + ); } } diff --git a/src/Core/API/API.Specs/Steps/AuthSteps.cs b/src/Core/API/API.Specs/Steps/AuthSteps.cs index 06a273b..8f714cc 100644 --- a/src/Core/API/API.Specs/Steps/AuthSteps.cs +++ b/src/Core/API/API.Specs/Steps/AuthSteps.cs @@ -300,9 +300,16 @@ public class AuthSteps(ScenarioContext scenario) }; var body = JsonSerializer.Serialize(registrationData); - var requestMessage = new HttpRequestMessage(HttpMethod.Post, "/api/auth/register") + var requestMessage = new HttpRequestMessage( + HttpMethod.Post, + "/api/auth/register" + ) { - Content = new StringContent(body, System.Text.Encoding.UTF8, "application/json"), + Content = new StringContent( + body, + System.Text.Encoding.UTF8, + "application/json" + ), }; var response = await client.SendAsync(requestMessage); @@ -318,9 +325,16 @@ public class AuthSteps(ScenarioContext scenario) var loginData = new { username = "test.user", password = "password" }; var body = JsonSerializer.Serialize(loginData); - var requestMessage = new HttpRequestMessage(HttpMethod.Post, "/api/auth/login") + var requestMessage = new HttpRequestMessage( + HttpMethod.Post, + "/api/auth/login" + ) { - Content = new StringContent(body, System.Text.Encoding.UTF8, "application/json"), + Content = new StringContent( + body, + System.Text.Encoding.UTF8, + "application/json" + ), }; var response = await client.SendAsync(requestMessage); @@ -330,13 +344,17 @@ public class AuthSteps(ScenarioContext scenario) var root = doc.RootElement; if (root.TryGetProperty("payload", out var payloadElem)) { - if (payloadElem.TryGetProperty("accessToken", out var tokenElem) || - payloadElem.TryGetProperty("AccessToken", out tokenElem)) + if ( + payloadElem.TryGetProperty("accessToken", out var tokenElem) + || payloadElem.TryGetProperty("AccessToken", out tokenElem) + ) { scenario["accessToken"] = tokenElem.GetString(); } - if (payloadElem.TryGetProperty("refreshToken", out var refreshElem) || - payloadElem.TryGetProperty("RefreshToken", out refreshElem)) + if ( + payloadElem.TryGetProperty("refreshToken", out var refreshElem) + || payloadElem.TryGetProperty("RefreshToken", out refreshElem) + ) { scenario["refreshToken"] = refreshElem.GetString(); } @@ -363,13 +381,20 @@ public class AuthSteps(ScenarioContext scenario) scenario["confirmationToken"] = "valid-confirmation-token"; } - [When("I submit a request to a protected endpoint with a valid access token")] + [When( + "I submit a request to a protected endpoint with a valid access token" + )] public async Task WhenISubmitARequestToAProtectedEndpointWithAValidAccessToken() { var client = GetClient(); - var token = scenario.TryGetValue("accessToken", out var t) ? t : "invalid-token"; + var token = scenario.TryGetValue("accessToken", out var t) + ? t + : "invalid-token"; - var requestMessage = new HttpRequestMessage(HttpMethod.Get, "/api/protected") + var requestMessage = new HttpRequestMessage( + HttpMethod.Get, + "/api/protected" + ) { Headers = { { "Authorization", $"Bearer {token}" } }, }; @@ -378,11 +403,16 @@ public class AuthSteps(ScenarioContext scenario) scenario[ResponseKey] = response; } - [When("I submit a request to a protected endpoint with an invalid access token")] + [When( + "I submit a request to a protected endpoint with an invalid access token" + )] public async Task WhenISubmitARequestToAProtectedEndpointWithAnInvalidAccessToken() { var client = GetClient(); - var requestMessage = new HttpRequestMessage(HttpMethod.Get, "/api/protected") + var requestMessage = new HttpRequestMessage( + HttpMethod.Get, + "/api/protected" + ) { Headers = { { "Authorization", "Bearer invalid-token-format" } }, }; @@ -395,12 +425,21 @@ public class AuthSteps(ScenarioContext scenario) public async Task WhenISubmitAConfirmationRequestWithTheValidToken() { var client = GetClient(); - var token = scenario.TryGetValue("confirmationToken", out var t) ? t : "valid-token"; + var token = scenario.TryGetValue("confirmationToken", out var t) + ? t + : "valid-token"; var body = JsonSerializer.Serialize(new { token }); - var requestMessage = new HttpRequestMessage(HttpMethod.Post, "/api/auth/confirm") + var requestMessage = new HttpRequestMessage( + HttpMethod.Post, + "/api/auth/confirm" + ) { - Content = new StringContent(body, System.Text.Encoding.UTF8, "application/json"), + Content = new StringContent( + body, + System.Text.Encoding.UTF8, + "application/json" + ), }; var response = await client.SendAsync(requestMessage); @@ -413,11 +452,20 @@ public class AuthSteps(ScenarioContext scenario) public async Task WhenISubmitAConfirmationRequestWithAMalformedToken() { var client = GetClient(); - var body = JsonSerializer.Serialize(new { token = "malformed-token-not-jwt" }); + var body = JsonSerializer.Serialize( + new { token = "malformed-token-not-jwt" } + ); - var requestMessage = new HttpRequestMessage(HttpMethod.Post, "/api/auth/confirm") + var requestMessage = new HttpRequestMessage( + HttpMethod.Post, + "/api/auth/confirm" + ) { - Content = new StringContent(body, System.Text.Encoding.UTF8, "application/json"), + Content = new StringContent( + body, + System.Text.Encoding.UTF8, + "application/json" + ), }; var response = await client.SendAsync(requestMessage); @@ -430,12 +478,21 @@ public class AuthSteps(ScenarioContext scenario) public async Task WhenISubmitARefreshTokenRequestWithTheValidRefreshToken() { var client = GetClient(); - var token = scenario.TryGetValue("refreshToken", out var t) ? t : "valid-refresh-token"; + var token = scenario.TryGetValue("refreshToken", out var t) + ? t + : "valid-refresh-token"; var body = JsonSerializer.Serialize(new { refreshToken = token }); - var requestMessage = new HttpRequestMessage(HttpMethod.Post, "/api/auth/refresh") + var requestMessage = new HttpRequestMessage( + HttpMethod.Post, + "/api/auth/refresh" + ) { - Content = new StringContent(body, System.Text.Encoding.UTF8, "application/json"), + Content = new StringContent( + body, + System.Text.Encoding.UTF8, + "application/json" + ), }; var response = await client.SendAsync(requestMessage); @@ -449,11 +506,20 @@ public class AuthSteps(ScenarioContext scenario) { var client = GetClient(); // Use an expired token - var body = JsonSerializer.Serialize(new { refreshToken = "expired-refresh-token" }); + var body = JsonSerializer.Serialize( + new { refreshToken = "expired-refresh-token" } + ); - var requestMessage = new HttpRequestMessage(HttpMethod.Post, "/api/auth/refresh") + var requestMessage = new HttpRequestMessage( + HttpMethod.Post, + "/api/auth/refresh" + ) { - Content = new StringContent(body, System.Text.Encoding.UTF8, "application/json"), + Content = new StringContent( + body, + System.Text.Encoding.UTF8, + "application/json" + ), }; var response = await client.SendAsync(requestMessage); @@ -468,9 +534,16 @@ public class AuthSteps(ScenarioContext scenario) var client = GetClient(); var body = JsonSerializer.Serialize(new { }); - var requestMessage = new HttpRequestMessage(HttpMethod.Post, "/api/auth/refresh") + var requestMessage = new HttpRequestMessage( + HttpMethod.Post, + "/api/auth/refresh" + ) { - Content = new StringContent(body, System.Text.Encoding.UTF8, "application/json"), + Content = new StringContent( + body, + System.Text.Encoding.UTF8, + "application/json" + ), }; var response = await client.SendAsync(requestMessage); @@ -483,9 +556,16 @@ public class AuthSteps(ScenarioContext scenario) public async Task WhenISubmitARefreshTokenRequestUsingAGETRequest() { var client = GetClient(); - var requestMessage = new HttpRequestMessage(HttpMethod.Get, "/api/auth/refresh") + var requestMessage = new HttpRequestMessage( + HttpMethod.Get, + "/api/auth/refresh" + ) { - Content = new StringContent("{}", System.Text.Encoding.UTF8, "application/json"), + Content = new StringContent( + "{}", + System.Text.Encoding.UTF8, + "application/json" + ), }; var response = await client.SendAsync(requestMessage); @@ -497,7 +577,10 @@ public class AuthSteps(ScenarioContext scenario) public async Task WhenISubmitARequestToAProtectedEndpointWithoutAnAccessToken() { var client = GetClient(); - var requestMessage = new HttpRequestMessage(HttpMethod.Get, "/api/protected"); + var requestMessage = new HttpRequestMessage( + HttpMethod.Get, + "/api/protected" + ); var response = await client.SendAsync(requestMessage); scenario[ResponseKey] = response; @@ -514,16 +597,22 @@ public class AuthSteps(ScenarioContext scenario) public void GivenIHaveAnAccessTokenSignedWithTheWrongSecret() { // Create a token with a different secret - scenario["accessToken"] = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"; + scenario["accessToken"] = + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"; } [When("I submit a request to a protected endpoint with the expired token")] public async Task WhenISubmitARequestToAProtectedEndpointWithTheExpiredToken() { var client = GetClient(); - var token = scenario.TryGetValue("accessToken", out var t) ? t : "expired-token"; + var token = scenario.TryGetValue("accessToken", out var t) + ? t + : "expired-token"; - var requestMessage = new HttpRequestMessage(HttpMethod.Get, "/api/protected") + var requestMessage = new HttpRequestMessage( + HttpMethod.Get, + "/api/protected" + ) { Headers = { { "Authorization", $"Bearer {token}" } }, }; @@ -536,9 +625,14 @@ public class AuthSteps(ScenarioContext scenario) public async Task WhenISubmitARequestToAProtectedEndpointWithTheTamperedToken() { var client = GetClient(); - var token = scenario.TryGetValue("accessToken", out var t) ? t : "tampered-token"; + var token = scenario.TryGetValue("accessToken", out var t) + ? t + : "tampered-token"; - var requestMessage = new HttpRequestMessage(HttpMethod.Get, "/api/protected") + var requestMessage = new HttpRequestMessage( + HttpMethod.Get, + "/api/protected" + ) { Headers = { { "Authorization", $"Bearer {token}" } }, }; @@ -547,13 +641,20 @@ public class AuthSteps(ScenarioContext scenario) scenario[ResponseKey] = response; } - [When("I submit a request to a protected endpoint with my refresh token instead of access token")] + [When( + "I submit a request to a protected endpoint with my refresh token instead of access token" + )] public async Task WhenISubmitARequestToAProtectedEndpointWithMyRefreshTokenInsteadOfAccessToken() { var client = GetClient(); - var token = scenario.TryGetValue("refreshToken", out var t) ? t : "refresh-token"; + var token = scenario.TryGetValue("refreshToken", out var t) + ? t + : "refresh-token"; - var requestMessage = new HttpRequestMessage(HttpMethod.Get, "/api/protected") + var requestMessage = new HttpRequestMessage( + HttpMethod.Get, + "/api/protected" + ) { Headers = { { "Authorization", $"Bearer {token}" } }, }; @@ -568,13 +669,20 @@ public class AuthSteps(ScenarioContext scenario) scenario["confirmationToken"] = "valid-confirmation-token"; } - [When("I submit a request to a protected endpoint with my confirmation token instead of access token")] + [When( + "I submit a request to a protected endpoint with my confirmation token instead of access token" + )] public async Task WhenISubmitARequestToAProtectedEndpointWithMyConfirmationTokenInsteadOfAccessToken() { var client = GetClient(); - var token = scenario.TryGetValue("confirmationToken", out var t) ? t : "confirmation-token"; + var token = scenario.TryGetValue("confirmationToken", out var t) + ? t + : "confirmation-token"; - var requestMessage = new HttpRequestMessage(HttpMethod.Get, "/api/protected") + var requestMessage = new HttpRequestMessage( + HttpMethod.Get, + "/api/protected" + ) { Headers = { { "Authorization", $"Bearer {token}" } }, };