using System.IdentityModel.Tokens.Jwt; using System.Net; using System.Net.Http.Headers; using System.Security; using System.Text; using Azaion.CommonSecurity.DTO; using Newtonsoft.Json; namespace Azaion.CommonSecurity.Services; public class AzaionApiClient(HttpClient httpClient) : IDisposable { const string JSON_MEDIA = "application/json"; private string Email { get; set; } = null!; private SecureString Password { get; set; } = new(); private string JwtToken { get; set; } = null!; public User User { get; set; } = null!; public static AzaionApiClient Create(ApiCredentials credentials) { ApiConfig apiConfig; try { if (!File.Exists(SecurityConstants.CONFIG_PATH)) throw new FileNotFoundException(SecurityConstants.CONFIG_PATH); var configStr = File.ReadAllText(SecurityConstants.CONFIG_PATH); apiConfig = JsonConvert.DeserializeObject(configStr)!.ApiConfig; } catch (Exception e) { Console.WriteLine(e); apiConfig = new ApiConfig { Url = SecurityConstants.DEFAULT_API_URL, RetryCount = SecurityConstants.DEFAULT_API_RETRY_COUNT , TimeoutSeconds = SecurityConstants.DEFAULT_API_TIMEOUT_SECONDS }; } var api = new AzaionApiClient(new HttpClient { BaseAddress = new Uri(apiConfig.Url), Timeout = TimeSpan.FromSeconds(apiConfig.TimeoutSeconds) }); api.EnterCredentials(credentials); return api; } public void EnterCredentials(ApiCredentials credentials) { if (string.IsNullOrWhiteSpace(credentials.Email) || string.IsNullOrWhiteSpace(credentials.Password)) throw new Exception("Email or password is empty!"); Email = credentials.Email; Password = credentials.Password.ToSecureString(); } public async Task GetResource(string fileName, string password, HardwareInfo hardware) { var response = await Send(httpClient, new HttpRequestMessage(HttpMethod.Post, "/resources/get") { Content = new StringContent(JsonConvert.SerializeObject(new { fileName, password, hardware }), Encoding.UTF8, JSON_MEDIA) }); return await response.Content.ReadAsStreamAsync(); } private async Task Authorize() { if (string.IsNullOrEmpty(Email) || Password.Length == 0) throw new Exception("Email or password is empty! Please do EnterCredentials first!"); var payload = new { email = Email, password = Password.ToRealString() }; var response = await httpClient.PostAsync( "login", new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, JSON_MEDIA)); if (!response.IsSuccessStatusCode) throw new Exception($"EnterCredentials failed: {response.StatusCode}"); var responseData = await response.Content.ReadAsStringAsync(); var result = JsonConvert.DeserializeObject(responseData); if (string.IsNullOrEmpty(result?.Token)) throw new Exception("JWT Token not found in response"); var handler = new JwtSecurityTokenHandler(); var token = handler.ReadJwtToken(result.Token); User = new User(token.Claims); JwtToken = result.Token; } private async Task Send(HttpClient client, HttpRequestMessage request) { if (string.IsNullOrEmpty(JwtToken)) await Authorize(); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", JwtToken); var response = await client.SendAsync(request); if (response.StatusCode == HttpStatusCode.Unauthorized) { await Authorize(); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", JwtToken); response = await client.SendAsync(request); } if (response.IsSuccessStatusCode) return response; var result = await response.Content.ReadAsStringAsync(); throw new Exception($"Failed: {response.StatusCode}! Result: {result}"); } public void Dispose() { httpClient.Dispose(); Password.Dispose(); } }