using System.Net.Http.Json; using System.Text.Json; using JdeScoping.Core.Models.Auth; using Microsoft.JSInterop; namespace JdeScoping.Client.Services; /// /// Encrypts login credentials using Web Crypto API via JavaScript interop. /// Uses RSA-OAEP with SHA-256 to encrypt credentials before transmission. /// public class CryptoService : ICryptoService { private readonly HttpClient _httpClient; private readonly IJSRuntime _jsRuntime; private string? _cachedPublicKeyPem; private readonly SemaphoreSlim _keyLock = new(1, 1); public CryptoService(HttpClient httpClient, IJSRuntime jsRuntime) { _httpClient = httpClient; _jsRuntime = jsRuntime; } /// public async Task EncryptLoginAsync(LoginModel model) { var publicKeyPem = await GetOrFetchPublicKeyAsync(); var json = JsonSerializer.Serialize(model); // Use JavaScript interop to encrypt with RSA-OAEP via browser's SubtleCrypto API var encryptedBase64 = await _jsRuntime.InvokeAsync( "jdeScopingInterop.rsaEncrypt", publicKeyPem, json); return encryptedBase64; } private async Task GetOrFetchPublicKeyAsync() { if (_cachedPublicKeyPem is not null) return _cachedPublicKeyPem; await _keyLock.WaitAsync(); try { if (_cachedPublicKeyPem is not null) return _cachedPublicKeyPem; var response = await _httpClient.GetFromJsonAsync("api/auth/public-key") ?? throw new InvalidOperationException("Failed to fetch public key from server"); _cachedPublicKeyPem = response.PublicKeyPem; return _cachedPublicKeyPem; } finally { _keyLock.Release(); } } }