Server URL validation

This commit is contained in:
Chris Bell 2025-03-28 14:59:47 -05:00
parent 2e70c5224c
commit 93d5d4fc5d
7 changed files with 163 additions and 29 deletions

View File

@ -14,25 +14,35 @@ public class DatabaseController : ControllerBase
_context = context; _context = context;
} }
[HttpGet("verify-users-table")] // [HttpGet("verify-users-table")]
public async Task<IActionResult> VerifyUsersTable() // public async Task<IActionResult> VerifyUsersTable()
// {
// try
// {
// var tableExists = await _context.Users.AnyAsync();
// return Ok(new
// {
// Message = "Users table exists and can be queried.",
// CanQuery = true
// });
// }
// catch (Exception ex)
// {
// return StatusCode(500, new
// {
// Message = "Error accessing users table",
// Error = ex.Message
// });
// }
// }
[HttpGet("validate-server")]
public IActionResult ValidateServer()
{ {
try return Ok(new
{ {
var tableExists = await _context.Users.AnyAsync(); IsValid = true,
return Ok(new Message = "SessionZero server is running.",
{ });
Message = "Users table exists and can be queried.",
CanQuery = true
});
}
catch (Exception ex)
{
return StatusCode(500, new
{
Message = "Error accessing users table",
Error = ex.Message
});
}
} }
} }

View File

@ -0,0 +1,10 @@
<component name="libraryTable">
<library name="GdSdk Master" type="GdScript">
<properties path="$USER_HOME$/.cache/JetBrains/Rider2024.3/projects/.idea.sessionzero.f839d0be/sdk/GdSdk Master" version="Master" date="2024-06-01T15:14:16.000+02:00" />
<CLASSES />
<JAVADOC />
<SOURCES>
<root url="file://$USER_HOME$/.cache/JetBrains/Rider2024.3/projects/.idea.sessionzero.f839d0be/sdk/GdSdk Master" />
</SOURCES>
</library>
</component>

View File

@ -1,4 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="VcsDirectoryMappings" defaultProject="true" /> <component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
</component>
</project> </project>

View File

@ -2,7 +2,10 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net.Http; using System.Net.Http;
using System.Text.Json; using System.Text.Json;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Godot;
using HttpClient = System.Net.Http.HttpClient;
namespace SessionZeroClient.API; namespace SessionZeroClient.API;
@ -12,11 +15,67 @@ public class ApiHandler : IApiHandler
public ApiHandler() public ApiHandler()
{ {
_httpClient = new HttpClient(); 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) 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 apiString = $"{url}/api/Auth/register";
var requestBody = new Dictionary<string, string> var requestBody = new Dictionary<string, string>
{ {
@ -39,8 +98,23 @@ public class ApiHandler : IApiHandler
return responseString; 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) 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 apiString = $"{url}/api/Auth/login";
var requestBody = new Dictionary<string, string> var requestBody = new Dictionary<string, string>
{ {
@ -60,4 +134,11 @@ public class ApiHandler : IApiHandler
var responseString = await response.Content.ReadAsStringAsync(); var responseString = await response.Content.ReadAsStringAsync();
return responseString; return responseString;
} }
public class ServerUrlValidationResponse
{
public bool IsValid { get; set; }
public string Message { get; set; }
}
} }

View File

@ -4,6 +4,7 @@ namespace SessionZeroClient.API;
public interface IApiHandler public interface IApiHandler
{ {
Task<bool> ValidateServerUrl(string url);
Task<string> Register(string url, string username, string email, string password); Task<string> Register(string url, string username, string email, string password);
Task<string> Login(string url, string username, string password); Task<string> Login(string url, string username, string password);
} }

View File

@ -1,6 +1,8 @@
using Godot; using Godot;
using System; using System;
using System.Threading.Tasks;
using SessionZeroClient; using SessionZeroClient;
using SessionZeroClient.API;
public partial class AccountScreenLogic : Node public partial class AccountScreenLogic : Node
{ {
@ -38,11 +40,13 @@ public partial class AccountScreenLogic : Node
[Export] Button BackButton { get; set; } [Export] Button BackButton { get; set; }
private IApiHandler _apiHandler;
private AccountManager _accountManager; private AccountManager _accountManager;
private string _url = ""; private string _url = "";
public void Init(AccountManager accountManager) public void Init(IApiHandler apiHandler, AccountManager accountManager)
{ {
_apiHandler = apiHandler;
_accountManager = accountManager; _accountManager = accountManager;
SetupSignals(); SetupSignals();
InitialState(); InitialState();
@ -105,16 +109,24 @@ public partial class AccountScreenLogic : Node
BackButton.Pressed += BackButtonPressed; BackButton.Pressed += BackButtonPressed;
} }
private void RegisterSelectionButtonPressed() private async void RegisterSelectionButtonPressed()
{ {
_url = UrlLineEdit.Text; // TODO: Add validation bool isValidServer = await ValidateServerUrl(UrlLineEdit.Text);
RegisterState(); if (isValidServer)
{
_url = UrlLineEdit.Text;
RegisterState();
}
} }
private void LoginSelectionButtonPressed() private async void LoginSelectionButtonPressed()
{ {
_url = UrlLineEdit.Text; // TODO: Add validation bool isValidServer = await ValidateServerUrl(UrlLineEdit.Text);
LoginState(); if (isValidServer)
{
_url = UrlLineEdit.Text;
LoginState();
}
} }
private async void RegisterButtonPressed() private async void RegisterButtonPressed()
@ -154,6 +166,24 @@ public partial class AccountScreenLogic : Node
} }
} }
private async Task<bool> ValidateServerUrl(string url)
{
if (string.IsNullOrEmpty(url))
{
return false;
}
try
{
return await _apiHandler.ValidateServerUrl(url);
}
catch (Exception ex)
{
GD.PrintErr($"Server validation error: {ex.Message}");
return false;
}
}
private void Logout() private void Logout()
{ {
_accountManager.Logout(); _accountManager.Logout();

View File

@ -25,7 +25,7 @@ public partial class Main : Node
try try
{ {
_accountScreenLogic = AccountScreenScene.Instantiate() as AccountScreenLogic; _accountScreenLogic = AccountScreenScene.Instantiate() as AccountScreenLogic;
_accountScreenLogic.Init(_accountManager); _accountScreenLogic.Init(_apiHandler, _accountManager);
MainCanvasLayer.AddChild(_accountScreenLogic); MainCanvasLayer.AddChild(_accountScreenLogic);
} }
catch (Exception e) catch (Exception e)