Modularize project structure by splitting responsibilities into distinct files and namespaces. Add helper methods for authentication and JSON operations.
This commit is contained in:
80
Helper/AuthHelper.cs
Normal file
80
Helper/AuthHelper.cs
Normal file
@@ -0,0 +1,80 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using FsTool.Tasks;
|
||||
|
||||
namespace FsTool.Helpers;
|
||||
|
||||
public static class AuthHelper
|
||||
{
|
||||
private static async Task<string?> LoadCsrfTokenAsync()
|
||||
{
|
||||
if (!File.Exists("csrf_token.json")) return null;
|
||||
|
||||
var json = await File.ReadAllTextAsync("csrf_token.json");
|
||||
var tokenInfo = JsonSerializer.Deserialize<JsonObject>(json);
|
||||
|
||||
if (tokenInfo == null) return null;
|
||||
|
||||
var token = tokenInfo["token"]?.GetValue<string>();
|
||||
var expiresAtString = tokenInfo["expiresAt"]?.GetValue<string>();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(token) || string.IsNullOrWhiteSpace(expiresAtString)) return null;
|
||||
|
||||
if (DateTime.TryParse(expiresAtString, out var expiresAt))
|
||||
{
|
||||
if (DateTime.UtcNow < expiresAt.ToUniversalTime())
|
||||
return token;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
internal static async Task StoreCsrfTokenAsync(string? csrfToken, DateTime expiration)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(csrfToken)) return;
|
||||
|
||||
var tokenInfo = new
|
||||
{
|
||||
token = csrfToken,
|
||||
expiresAt = expiration
|
||||
};
|
||||
|
||||
var json = JsonSerializer.Serialize(tokenInfo, new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true
|
||||
});
|
||||
|
||||
await File.WriteAllTextAsync("csrf_token.json", json);
|
||||
}
|
||||
|
||||
public static async Task EnsureAuthenticationAsync(HttpClient httpClient)
|
||||
{
|
||||
// Check if header already contains a CSRF token
|
||||
if (httpClient.DefaultRequestHeaders.TryGetValues("X-CSRF-Token", out var existingTokens))
|
||||
{
|
||||
var existingToken = existingTokens.FirstOrDefault();
|
||||
if (!string.IsNullOrWhiteSpace(existingToken))
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to load CSRF token from file
|
||||
var csrfToken = await LoadCsrfTokenAsync();
|
||||
|
||||
// If no valid token found, call login endpoint to get a new one
|
||||
if (string.IsNullOrWhiteSpace(csrfToken))
|
||||
csrfToken = await UserTasks.CallLoginEndpointAsync(httpClient);
|
||||
|
||||
// Set CSRF token in HTTP client headers
|
||||
if (!string.IsNullOrWhiteSpace(csrfToken))
|
||||
{
|
||||
csrfToken = csrfToken.ReplaceLineEndings(string.Empty);
|
||||
|
||||
httpClient.DefaultRequestHeaders.Remove("X-CSRF-Token");
|
||||
httpClient.DefaultRequestHeaders.Add("X-CSRF-Token", csrfToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
41
Helper/Extensions.cs
Normal file
41
Helper/Extensions.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using System.Text;
|
||||
using System.Text.Json.Nodes;
|
||||
|
||||
namespace FsTool.Helpers
|
||||
{
|
||||
public static class Extensions
|
||||
{
|
||||
#region Public Method FsPostAsync
|
||||
|
||||
/// <summary>
|
||||
/// Sends a POST request to the specified URI with the provided JSON content.
|
||||
/// </summary>
|
||||
/// <param name="httpClient">The instance of <see cref="HttpClient" /> used to send the request.</param>
|
||||
/// <param name="requestUri">The URI to which the request is sent.</param>
|
||||
/// <param name="jsonObject">The JSON object to include in the request body.</param>
|
||||
/// <returns>A task that represents the asynchronous operation. The task result contains the HTTP response.</returns>
|
||||
public static async Task<HttpResponseMessage> FsPostAsync(this HttpClient httpClient, string requestUri, JsonObject jsonObject)
|
||||
{
|
||||
var content = new StringContent(jsonObject.ToString(), Encoding.UTF8, "application/json");
|
||||
content.Headers.ContentType = new("application/json");
|
||||
return await httpClient.PostAsync(requestUri, content);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Method ToList
|
||||
|
||||
/// <summary>
|
||||
/// Converts the specified JSON node into a list of non-null <see cref="JsonNode" /> elements.
|
||||
/// </summary>
|
||||
/// <param name="node">The <see cref="JsonNode" /> to be converted. If null, an empty list is returned.</param>
|
||||
/// <returns>A list of <see cref="JsonNode" /> instances containing non-null elements.</returns>
|
||||
public static List<JsonNode> ToList(this JsonNode? node)
|
||||
{
|
||||
var array = node?.AsArray() ?? [];
|
||||
return array.Where(x => x != null).Select(x => x!).ToList();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user