diff --git a/SharedLibraryCore/Dtos/ClientInfoResult.cs b/SharedLibraryCore/Dtos/ClientInfoResult.cs new file mode 100644 index 00000000..22ae8e6c --- /dev/null +++ b/SharedLibraryCore/Dtos/ClientInfoResult.cs @@ -0,0 +1,17 @@ +using System; + +namespace SharedLibraryCore.Dtos; + +public class ClientInfoResult +{ + public int ClientId { get; set; } + public string Name { get; set; } + public string Level { get; set; } + public long NetworkId { get; set; } + public string GameName { get; set; } + public string? Tag { get; set; } + public DateTime FirstConnection { get; set; } + public DateTime LastConnection { get; set; } + public int TotalConnectionTime { get; set; } + public int Connections { get; set; } +} diff --git a/WebfrontCore/Controllers/API/ClientController.cs b/WebfrontCore/Controllers/API/ClientController.cs index 764e2662..421dd72b 100644 --- a/WebfrontCore/Controllers/API/ClientController.cs +++ b/WebfrontCore/Controllers/API/ClientController.cs @@ -3,10 +3,12 @@ using SharedLibraryCore.Dtos; using SharedLibraryCore.Interfaces; using System; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Security.Claims; using System.Threading.Tasks; +using Data.Models; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.Extensions.Logging; @@ -24,20 +26,15 @@ namespace WebfrontCore.Controllers.API /// [ApiController] [Route("api/[controller]")] - public class ClientController : BaseController + public class ClientController( + ILogger logger, + IResourceQueryHelper clientQueryHelper, + ClientService clientService, + IManager manager, + IMetaServiceV2 metaService) + : BaseController(manager) { - private readonly IResourceQueryHelper _clientQueryHelper; - private readonly ILogger _logger; - private readonly ClientService _clientService; - - public ClientController(ILogger logger, - IResourceQueryHelper clientQueryHelper, - ClientService clientService, IManager manager) : base(manager) - { - _logger = logger; - _clientQueryHelper = clientQueryHelper; - _clientService = clientService; - } + private readonly ILogger _logger = logger; [HttpGet("find")] [ProducesResponseType(StatusCodes.Status200OK)] @@ -47,16 +44,16 @@ public async Task FindAsync([FromQuery] FindClientRequest request { if (!ModelState.IsValid) { - return BadRequest(new ErrorResponse() + return BadRequest(new ErrorResponse { Messages = ModelState.Values - .SelectMany(_value => _value.Errors.Select(_error => _error.ErrorMessage)).ToArray() + .SelectMany(value => value.Errors.Select(error => error.ErrorMessage)).ToArray() }); } try { - var results = await _clientQueryHelper.QueryResource(request); + var results = await clientQueryHelper.QueryResource(request); return Ok(new FindClientResponse { @@ -64,28 +61,58 @@ public async Task FindAsync([FromQuery] FindClientRequest request Clients = results.Results }); } - catch (Exception e) { - _logger.LogWarning(e, "Failed to retrieve clients with query - {@request}", request); + _logger.LogWarning(e, "Failed to retrieve clients with query - {@Request}", request); + return StatusCode(StatusCodes.Status500InternalServerError, new ErrorResponse { Messages = [e.Message] }); + } + } + + [HttpGet("{clientId:int}")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + public async Task GetPlayerInfoAsync([FromRoute] int clientId) + { + try + { + var clientInfo = await clientService.Get(clientId); + if (clientInfo is null) + { + return BadRequest("Could not find client"); + } + + var metaResult = await metaService + .GetPersistentMetaByLookup(EFMeta.ClientTagV2, EFMeta.ClientTagNameV2, clientInfo.ClientId); - return StatusCode(StatusCodes.Status500InternalServerError, new ErrorResponse() + return Ok(new ClientInfoResult { - Messages = new[] {e.Message} + ClientId = clientInfo.ClientId, + Name = clientInfo.CleanedName, + Level = clientInfo.Level.ToLocalizedLevelName(), + NetworkId = clientInfo.NetworkId, + GameName = clientInfo.GameName.ToString(), + Tag = metaResult?.Value, + FirstConnection = clientInfo.FirstConnection, + LastConnection = clientInfo.LastConnection, + TotalConnectionTime = clientInfo.TotalConnectionTime, + Connections = clientInfo.Connections, }); } + catch (Exception e) + { + _logger.LogWarning(e, "Failed to retrieve information for Client - {ClientId}", clientId); + return StatusCode(StatusCodes.Status500InternalServerError, new ErrorResponse { Messages = [e.Message] }); + } } - [HttpPost("{clientId:int}/login")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task Login([FromRoute] int clientId, - [FromBody, Required] PasswordRequest request) + public async Task Login([FromRoute] int clientId, [FromBody, Required] PasswordRequest request) { - if (clientId == 0) + if (clientId is 0) { return Unauthorized(); } @@ -97,7 +124,7 @@ public async Task Login([FromRoute] int clientId, try { - var privilegedClient = await _clientService.GetClientForLogin(clientId); + var privilegedClient = await clientService.GetClientForLogin(clientId); var loginSuccess = false; if (!Authorized) @@ -107,51 +134,49 @@ public async Task Login([FromRoute] int clientId, ClientId = clientId, Token = request.Password }; - - loginSuccess = - Manager.TokenAuthenticator.AuthorizeToken(tokenData) || - (await Task.FromResult(Hashing.Hash(request.Password, - privilegedClient.PasswordSalt)))[0] == privilegedClient.Password; + + loginSuccess = Manager.TokenAuthenticator.AuthorizeToken(tokenData) || + (await Task.FromResult(Hashing.Hash(request.Password, privilegedClient.PasswordSalt)))[0] == + privilegedClient.Password; } if (loginSuccess) { - var claims = new[] - { + List claims = + [ new Claim(ClaimTypes.NameIdentifier, privilegedClient.Name), new Claim(ClaimTypes.Role, privilegedClient.Level.ToString()), new Claim(ClaimTypes.Sid, privilegedClient.ClientId.ToString()), new Claim(ClaimTypes.PrimarySid, privilegedClient.NetworkId.ToString("X")) - }; + ]; var claimsIdentity = new ClaimsIdentity(claims, "login"); var claimsPrinciple = new ClaimsPrincipal(claimsIdentity); await SignInAsync(claimsPrinciple); - + Manager.AddEvent(new GameEvent { Origin = privilegedClient, Type = GameEvent.EventType.Login, Owner = Manager.GetServers().First(), - Data = HttpContext.Request.Headers.ContainsKey("X-Forwarded-For") - ? HttpContext.Request.Headers["X-Forwarded-For"].ToString() - : HttpContext.Connection.RemoteIpAddress.ToString() + Data = HttpContext.Request.Headers.TryGetValue("X-Forwarded-For", out var gameStringValues) + ? gameStringValues.ToString() + : HttpContext.Connection.RemoteIpAddress?.ToString() }); - + Manager.QueueEvent(new LoginEvent { Source = this, LoginSource = LoginEvent.LoginSourceType.Webfront, EntityId = Client.ClientId.ToString(), - Identifier = HttpContext.Request.Headers.ContainsKey("X-Forwarded-For") - ? HttpContext.Request.Headers["X-Forwarded-For"].ToString() + Identifier = HttpContext.Request.Headers.TryGetValue("X-Forwarded-For", out var loginStringValues) + ? loginStringValues.ToString() : HttpContext.Connection.RemoteIpAddress?.ToString() }); return Ok(); } } - catch (Exception) { return Unauthorized(); @@ -172,24 +197,23 @@ public async Task Logout() Origin = Client, Type = GameEvent.EventType.Logout, Owner = Manager.GetServers().First(), - Data = HttpContext.Request.Headers.ContainsKey("X-Forwarded-For") - ? HttpContext.Request.Headers["X-Forwarded-For"].ToString() - : HttpContext.Connection.RemoteIpAddress.ToString() + Data = HttpContext.Request.Headers.TryGetValue("X-Forwarded-For", out var gameStringValues) + ? gameStringValues.ToString() + : HttpContext.Connection.RemoteIpAddress?.ToString() }); - + Manager.QueueEvent(new LogoutEvent { Source = this, LoginSource = LoginEvent.LoginSourceType.Webfront, EntityId = Client.ClientId.ToString(), - Identifier = HttpContext.Request.Headers.ContainsKey("X-Forwarded-For") - ? HttpContext.Request.Headers["X-Forwarded-For"].ToString() + Identifier = HttpContext.Request.Headers.TryGetValue("X-Forwarded-For", out var logoutStringValues) + ? logoutStringValues.ToString() : HttpContext.Connection.RemoteIpAddress?.ToString() }); } - - await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); + await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); return Ok(); }