Files
FsToolbox/Cli/Tasks/UserTasks.cs
2025-12-12 08:23:19 +01:00

110 lines
4.3 KiB
C#

using System;
using System.Linq;
using System.Net.Http.Json;
using FsToolbox.Cli.Helper;
namespace FsToolbox.Cli.Tasks
{
public static class UserTasks
{
/// <summary>
/// Performs a login request using configured credentials and optional two-factor authentication.
/// </summary>
/// <param name="httpClient">The HTTP client used to send the request.</param>
/// <returns>The CSRF token when login succeeds; otherwise, <c>null</c>.</returns>
public static async Task<string?> CallLoginEndpointAsync(HttpClient httpClient)
{
var credentials = SettingsProvider.Current.Credentials;
if (string.IsNullOrWhiteSpace(credentials.Email) || string.IsNullOrWhiteSpace(credentials.Password))
{
Console.WriteLine("Email and password must be configured in appsettings.json.");
return null;
}
string? authCode = null;
if (credentials.TwoFactorEnabled)
{
Console.Write("Enter 2FA code: ");
authCode = Console.ReadLine()?.Trim();
if (string.IsNullOrWhiteSpace(authCode))
{
Console.WriteLine("A valid 2FA code is required when two-factor authentication is enabled.");
return null;
}
}
string? csrfToken = null;
object payload = credentials.TwoFactorEnabled
? new
{
email = credentials.Email,
password = credentials.Password,
code = authCode,
remember_me = true
}
: new
{
email = credentials.Email,
password = credentials.Password,
remember_me = true
};
var response = await httpClient.PostAsJsonAsync(Endpoints.UserLogin, payload);
// handle unsuccessful response
if (!response.IsSuccessStatusCode)
{
var responseBody = await response.Content.ReadAsStringAsync();
await Console.Error.WriteLineAsync($"Login failed ({(int)response.StatusCode} {response.ReasonPhrase}): {responseBody}");
return null;
}
// Read headers as dictionary
var headers = response.Headers.ToDictionary(h => h.Key, h => string.Join(", ", h.Value));
if (headers.TryGetValue("Set-Cookie", out var setCookieHeader))
{
// Split cookies by comma and semicolon
var cookies = setCookieHeader.Split([";"], StringSplitOptions.RemoveEmptyEntries);
var csrfTokenEntry = cookies.FirstOrDefault(c => c.Trim().StartsWith("FS_CSRF_TOKEN="));
csrfToken = csrfTokenEntry?.Split('=')[1];
if (string.IsNullOrWhiteSpace(csrfToken)) return null;
var expiryEntry = cookies.FirstOrDefault(c => c.Trim().StartsWith("expires="));
var expireString = expiryEntry?.Split('=')[1];
if (DateTime.TryParse(expireString, out var expiration))
await AuthHelper.StoreCsrfTokenAsync(csrfToken, expiration);
}
return csrfToken;
}
/// <summary>
/// Retrieves information about the current authenticated user.
/// </summary>
/// <param name="httpClient">The HTTP client used to send the request.</param>
/// <returns>A task that represents the asynchronous operation.</returns>
public static async Task GetCurrentUserAsync(HttpClient httpClient)
{
await AuthHelper.EnsureAuthenticationAsync(httpClient);
var response = await httpClient.GetAsync(Endpoints.UserCurrent);
// handle unsuccessful response
if (!response.IsSuccessStatusCode)
{
var responseBody = await response.Content.ReadAsStringAsync();
await Console.Error.WriteLineAsync($"Get current user failed ({(int)response.StatusCode} {response.ReasonPhrase}): {responseBody}");
return;
}
var content = await response.Content.ReadAsStringAsync();
Console.WriteLine("Current User Info:");
Console.WriteLine(content);
}
}
}