using System.Security.Cryptography; using System.Text; using System.Text.Json; using JdeScoping.Client.Services; using JdeScoping.Core.Models.Auth; using Microsoft.AspNetCore.Mvc.Testing; namespace JdeScoping.Api.IntegrationTests.ClientIntegration; /// /// Base class for API client integration tests. /// Provides shared HttpClient with cookie handling for auth state. /// [Collection("ClientIntegration")] public abstract class ClientIntegrationTestBase : IClassFixture { protected readonly TestWebApplicationFactory Factory; protected readonly HttpClient SharedClient; // API clients share the authenticated HttpClient protected readonly SearchApiClient SearchClient; protected readonly LookupApiClient LookupClient; protected readonly AuthApiClient AuthClient; protected readonly FileApiClient FileClient; protected ClientIntegrationTestBase(TestWebApplicationFactory factory) { Factory = factory; SharedClient = factory.CreateClient(new WebApplicationFactoryClientOptions { HandleCookies = true, AllowAutoRedirect = false }); // All clients share the same HttpClient (cookie container) SearchClient = new SearchApiClient(SharedClient); LookupClient = new LookupApiClient(SharedClient); FileClient = new FileApiClient(SharedClient); AuthClient = new AuthApiClient(SharedClient); } /// /// Performs login with encrypted credentials. /// protected async Task LoginAsync(string username = "testuser", string password = "testpass") { // Step 1: Get public key var publicKeyResult = await AuthClient.GetPublicKeyAsync(); if (!publicKeyResult.IsSuccess) throw new Exception("Failed to get public key"); // Step 2: Encrypt credentials var loginModel = new LoginModel { Username = username, Password = password }; var json = JsonSerializer.Serialize(loginModel); var plaintext = Encoding.UTF8.GetBytes(json); using var rsa = RSA.Create(); rsa.ImportFromPem(publicKeyResult.Value.PublicKeyPem); var ciphertext = rsa.Encrypt(plaintext, RSAEncryptionPadding.OaepSHA256); // Step 3: Login var encryptedRequest = new EncryptedLoginRequest(Convert.ToBase64String(ciphertext)); var loginResult = await AuthClient.LoginAsync(encryptedRequest); if (!loginResult.IsSuccess || !loginResult.Value.Success) throw new Exception($"Login failed: {loginResult.Value?.ErrorMessage ?? "Unknown error"}"); } /// /// Creates a fresh HttpClient without cookies for testing unauthorized scenarios. /// protected HttpClient CreateFreshClient() => Factory.CreateClient(new WebApplicationFactoryClientOptions { HandleCookies = false, AllowAutoRedirect = false }); }