451 lines
14 KiB
Plaintext
451 lines
14 KiB
Plaintext
using System;
|
|
using System.Collections.Generic;
|
|
using System.Net.Http;
|
|
using System.Text.Json;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Godot;
|
|
using HttpClient = System.Net.Http.HttpClient;
|
|
|
|
namespace SessionZeroClient.API;
|
|
|
|
public class ApiHandler : IApiHandler
|
|
{
|
|
private readonly HttpClient _httpClient;
|
|
|
|
public ApiHandler()
|
|
{
|
|
var handler = new HttpClientHandler
|
|
{
|
|
UseDefaultCredentials = true,
|
|
};
|
|
|
|
_httpClient = new HttpClient(handler)
|
|
{
|
|
Timeout = TimeSpan.FromSeconds(5),
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns true if the server URL is reachable valid, false otherwise.
|
|
/// </summary>
|
|
/// <param name="url"></param>
|
|
/// <returns></returns>
|
|
public async Task<bool> ValidateServerUrl(string url)
|
|
{
|
|
try
|
|
{
|
|
var apiString = $"{url}/api/Database/validate-server";
|
|
|
|
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
|
|
var response = await _httpClient.GetAsync(apiString, cts.Token);
|
|
|
|
if (!response.IsSuccessStatusCode)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
var responseString = await response.Content.ReadAsStringAsync(cts.Token);
|
|
|
|
var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
|
|
var validationResponse = JsonSerializer.Deserialize<ServerUrlValidationResponse>(responseString, options);
|
|
|
|
return validationResponse?.IsValid ?? false;
|
|
}
|
|
catch
|
|
{
|
|
throw new HttpRequestException($"Server {url} is invalid or not reachable.");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Register a new user with the server.
|
|
/// </summary>
|
|
/// <param name="url"></param>
|
|
/// <param name="username"></param>
|
|
/// <param name="email"></param>
|
|
/// <param name="password"></param>
|
|
/// <returns></returns>
|
|
/// <exception cref="HttpRequestException"></exception>
|
|
public async Task<string> Register(string url, string username, string email, string password)
|
|
{
|
|
bool isValidServer = await ValidateServerUrl(url);
|
|
if (!isValidServer)
|
|
{
|
|
throw new HttpRequestException($"Could not Register User, Server {url} is invalid or not reachable.");
|
|
}
|
|
|
|
var apiString = $"{url}/api/Auth/register";
|
|
var requestBody = new Dictionary<string, string>
|
|
{
|
|
{"username", username},
|
|
{"email", email},
|
|
{"password", password}
|
|
};
|
|
|
|
var jsonBody = JsonSerializer.Serialize(requestBody);
|
|
var content = new StringContent(jsonBody, System.Text.Encoding.UTF8, "application/json");
|
|
var response = await _httpClient.PostAsync(apiString, content);
|
|
|
|
if (!response.IsSuccessStatusCode)
|
|
{
|
|
// throw new HttpRequestException($"Register failed: {response.StatusCode}");
|
|
|
|
}
|
|
|
|
var responseString = await response.Content.ReadAsStringAsync();
|
|
return responseString;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Login to the server with the given username and password. Returns the JWT token if successful.
|
|
/// </summary>
|
|
/// <param name="url"></param>
|
|
/// <param name="username"></param>
|
|
/// <param name="password"></param>
|
|
/// <returns></returns>
|
|
/// <exception cref="HttpRequestException"></exception>
|
|
public async Task<string> Login(string url, string username, string password)
|
|
{
|
|
|
|
bool isValidServer = await ValidateServerUrl(url);
|
|
if (!isValidServer)
|
|
{
|
|
throw new HttpRequestException($"Could not Login, Server {url} is invalid or not reachable.");
|
|
}
|
|
|
|
var apiString = $"{url}/api/Auth/login";
|
|
var requestBody = new Dictionary<string, string>
|
|
{
|
|
{"username", username},
|
|
{"password", password}
|
|
};
|
|
|
|
var jsonBody = JsonSerializer.Serialize(requestBody);
|
|
var content = new StringContent(jsonBody, System.Text.Encoding.UTF8, "application/json");
|
|
var response = await _httpClient.PostAsync(apiString, content);
|
|
|
|
if (!response.IsSuccessStatusCode)
|
|
{
|
|
// throw new HttpRequestException($"Login failed: {response.StatusCode}");
|
|
}
|
|
|
|
var responseString = await response.Content.ReadAsStringAsync();
|
|
return responseString;
|
|
}
|
|
|
|
public class ServerUrlValidationResponse
|
|
{
|
|
public bool IsValid { get; set; }
|
|
public string Message { get; set; }
|
|
}
|
|
}
|
|
|
|
-----------------------------------------------------
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
namespace SessionZeroClient.API;
|
|
|
|
public interface IApiHandler
|
|
{
|
|
Task<bool> ValidateServerUrl(string url);
|
|
Task<string> Register(string url, string username, string email, string password);
|
|
Task<string> Login(string url, string username, string password);
|
|
}
|
|
|
|
------------------------------------------------------
|
|
|
|
using Godot;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text.Json;
|
|
using System.Threading.Tasks;
|
|
using SessionZeroClient.API;
|
|
|
|
namespace SessionZeroClient;
|
|
|
|
public class AccountManager(IApiHandler apiHandler)
|
|
{
|
|
public string Username { get; private set; } = "";
|
|
public string Email { get; private set; } = "";
|
|
public string Jwt { get; private set; } = "";
|
|
|
|
private IApiHandler _apiHandler = apiHandler;
|
|
|
|
public async Task<bool> Register(string url, string username, string email, string password)
|
|
{
|
|
var response = await _apiHandler.Register(url, username, email, password);
|
|
|
|
if (!string.IsNullOrEmpty(response))
|
|
{
|
|
var responseData = JsonSerializer.Deserialize<Dictionary<string, string>>(response);
|
|
if (responseData != null && responseData.ContainsKey("message") && responseData["message"] == "User registered successfully")
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public async Task<bool> Login(string url, string username, string password)
|
|
{
|
|
var response = await _apiHandler.Login(url, username, password);
|
|
|
|
if (!string.IsNullOrEmpty(response))
|
|
{
|
|
var responseData = JsonSerializer.Deserialize<Dictionary<string, string>>(response);
|
|
if (responseData != null && responseData.ContainsKey("token"))
|
|
{
|
|
Jwt = responseData["token"];
|
|
Username = username;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public void Logout()
|
|
{
|
|
Jwt = "";
|
|
Username = "";
|
|
Email = "";
|
|
}
|
|
}
|
|
|
|
-----------------------------------------------------------
|
|
|
|
using Godot;
|
|
using System;
|
|
using System.Threading.Tasks;
|
|
using SessionZeroClient;
|
|
using SessionZeroClient.API;
|
|
|
|
public partial class AccountScreenLogic : Node
|
|
{
|
|
[ExportGroup("UI Elements")]
|
|
// Selection Screen
|
|
[ExportSubgroup("Selection Screen")]
|
|
[Export] private VBoxContainer SelectionScreenVboxContainer { get; set; }
|
|
[Export] private Button RegisterSelectionButton { get; set; }
|
|
[Export] private Button LoginSelectionButton { get; set; }
|
|
[Export] private LineEdit UrlLineEdit { get; set; }
|
|
|
|
// Register Screen
|
|
[ExportSubgroup("Register Screen")]
|
|
[Export] private VBoxContainer RegisterScreenVboxContainer { get; set; }
|
|
[Export] private LineEdit RegisterUsernameLineEdit { get; set; }
|
|
[Export] private LineEdit RegisterEmailLineEdit { get; set; }
|
|
[Export] private LineEdit RegisterPasswordLineEdit { get; set; }
|
|
[Export] private Button RegisterButton { get; set; }
|
|
|
|
// Login Screen
|
|
[ExportSubgroup("Login Screen")]
|
|
[Export] private VBoxContainer LoginScreenVboxContainer { get; set; }
|
|
[Export] private LineEdit LoginUsernameLineEdit { get; set; }
|
|
[Export] private LineEdit LoginPasswordLineEdit { get; set; }
|
|
[Export] private Button LoginButton { get; set; }
|
|
|
|
// Account Screen
|
|
[ExportSubgroup("Account Screen")]
|
|
[Export] private VBoxContainer AccountScreenVboxContainer { get; set; }
|
|
[Export] private Label AccountScreenGreetingLabel { get; set; }
|
|
[Export] private Button LogoutButton { get; set; }
|
|
[Export] private Button OfflineModeButton { get; set; }
|
|
|
|
// Other
|
|
[ExportSubgroup("Other")]
|
|
[Export] Button BackButton { get; set; }
|
|
[Export] RichTextLabel StatusLabel { get; set; }
|
|
|
|
|
|
private IApiHandler _apiHandler;
|
|
private AccountManager _accountManager;
|
|
private string _url = "";
|
|
|
|
public void Init(IApiHandler apiHandler, AccountManager accountManager)
|
|
{
|
|
_apiHandler = apiHandler;
|
|
_accountManager = accountManager;
|
|
SetupSignals();
|
|
InitialState();
|
|
}
|
|
|
|
private void InitialState()
|
|
{
|
|
SelectionScreenVboxContainer.Visible = true;
|
|
RegisterScreenVboxContainer.Visible = false;
|
|
LoginScreenVboxContainer.Visible = false;
|
|
AccountScreenVboxContainer.Visible = false;
|
|
BackButton.Visible = false;
|
|
}
|
|
|
|
private void RegisterState()
|
|
{
|
|
SelectionScreenVboxContainer.Visible = false;
|
|
RegisterScreenVboxContainer.Visible = true;
|
|
LoginScreenVboxContainer.Visible = false;
|
|
AccountScreenVboxContainer.Visible = false;
|
|
BackButton.Visible = true;
|
|
}
|
|
|
|
private void LoginState()
|
|
{
|
|
SelectionScreenVboxContainer.Visible = false;
|
|
RegisterScreenVboxContainer.Visible = false;
|
|
LoginScreenVboxContainer.Visible = true;
|
|
AccountScreenVboxContainer.Visible = false;
|
|
BackButton.Visible = true;
|
|
}
|
|
|
|
private void AccountSuccessState()
|
|
{
|
|
SelectionScreenVboxContainer.Visible = false;
|
|
RegisterScreenVboxContainer.Visible = false;
|
|
LoginScreenVboxContainer.Visible = false;
|
|
AccountScreenVboxContainer.Visible = true;
|
|
BackButton.Visible = false;
|
|
|
|
AccountScreenGreetingLabel.Text = $"Welcome, {_accountManager.Username}!";
|
|
}
|
|
|
|
private void SetupSignals()
|
|
{
|
|
// Selection Screen
|
|
RegisterSelectionButton.Pressed += RegisterSelectionButtonPressed;
|
|
LoginSelectionButton.Pressed += LoginSelectionButtonPressed;
|
|
OfflineModeButton.Pressed += () => GD.Print("Offline mode not implemented yet.");
|
|
|
|
// Register Screen
|
|
RegisterButton.Pressed += RegisterButtonPressed;
|
|
|
|
// Login Screen
|
|
LoginButton.Pressed += LoginButtonPressed;
|
|
|
|
// Account Screen
|
|
LogoutButton.Pressed += Logout;
|
|
|
|
// Other
|
|
BackButton.Pressed += BackButtonPressed;
|
|
}
|
|
|
|
private async void RegisterSelectionButtonPressed()
|
|
{
|
|
bool isValidServer = await ValidateServerUrl(UrlLineEdit.Text);
|
|
if (isValidServer)
|
|
{
|
|
_url = UrlLineEdit.Text;
|
|
RegisterState();
|
|
}
|
|
}
|
|
|
|
private async void LoginSelectionButtonPressed()
|
|
{
|
|
bool isValidServer = await ValidateServerUrl(UrlLineEdit.Text);
|
|
if (isValidServer)
|
|
{
|
|
_url = UrlLineEdit.Text;
|
|
LoginState();
|
|
}
|
|
}
|
|
|
|
private async void RegisterButtonPressed()
|
|
{
|
|
var username = RegisterUsernameLineEdit.Text;
|
|
var email = RegisterEmailLineEdit.Text;
|
|
var password = RegisterPasswordLineEdit.Text;
|
|
|
|
var success = await _accountManager.Register(_url, username, email, password);
|
|
|
|
GD.Print($"Register success: {success}");
|
|
SetStatusLabel($"Register success: {success}", success ? Colors.Green : Colors.Red);
|
|
|
|
if (success)
|
|
{
|
|
var loginSuccess = await _accountManager.Login(_url, username, password);
|
|
|
|
GD.Print($"Login success: {loginSuccess}");
|
|
SetStatusLabel($"Login success: {loginSuccess}", loginSuccess ? Colors.Green : Colors.Red);
|
|
|
|
if (loginSuccess)
|
|
{
|
|
AccountSuccessState();
|
|
}
|
|
else
|
|
{
|
|
SetStatusLabel($"Login failed: {loginSuccess}", Colors.Red);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetStatusLabel("Registration failed", Colors.Red);
|
|
}
|
|
}
|
|
|
|
private async void LoginButtonPressed()
|
|
{
|
|
var username = LoginUsernameLineEdit.Text;
|
|
var password = LoginPasswordLineEdit.Text;
|
|
var success = await _accountManager.Login(_url, username, password);
|
|
|
|
GD.Print($"Login success: {success}");
|
|
SetStatusLabel($"Login success: {success}", success ? Colors.Green : Colors.Red);
|
|
|
|
if (success)
|
|
{
|
|
AccountSuccessState();
|
|
}
|
|
else
|
|
{
|
|
SetStatusLabel("Login failed. Check Username and Password.", Colors.Red);
|
|
}
|
|
}
|
|
|
|
private async Task<bool> ValidateServerUrl(string url)
|
|
{
|
|
if (string.IsNullOrEmpty(url))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
try
|
|
{
|
|
var isValid = await _apiHandler.ValidateServerUrl(url);
|
|
if (isValid)
|
|
{
|
|
GD.Print($"Server {url} is valid.");
|
|
SetStatusLabel($"Server {url} is valid.", Colors.Green);
|
|
}
|
|
|
|
return isValid;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
GD.Print($"Server validation error: {ex.Message}");
|
|
SetStatusLabel($"Server validation error: {ex.Message}", Colors.Red);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private void Logout()
|
|
{
|
|
_accountManager.Logout();
|
|
GD.Print("Logged out");
|
|
SetStatusLabel("Logged out", Colors.Cyan);
|
|
InitialState();
|
|
}
|
|
|
|
private void BackButtonPressed()
|
|
{
|
|
InitialState();
|
|
}
|
|
|
|
private void SetStatusLabel(string message, Color color)
|
|
{
|
|
StatusLabel.Text = $"[color={color.ToHtml()}] {message} [/color]";
|
|
}
|
|
}
|